前言
这两天,小面接手了一个前同事维护的项目,当看到系统里将上传的文件直接存放在单个服务器目录时,小面眼前一黑,目前存放在该目录的文件总量已有近千 G,如果服务部署到其它服务器,那还需要将该目录文件同步复制到服务器,唯一庆幸的是当前目录的文件没有丢失和损坏。
众所周知,将文件存储在单台服务器上存在性能瓶颈,容灾、垂直扩展性差等诸多问题。如果某天存储文件的服务突然 down 了怎么办?可能有人会说定时将文件系统备份,例如云服务器都有定时自动备份功能,当宕机的时候,迅速切换到另一台,但是这样需要人工来干预,且存在时延问题,线上系统会有几分钟的不可用。
另外,当存储的文件超过数百 T 的时候怎么办?单台服务器的网络性能也存在瓶颈等问题。
因此,系统在设计时就应该考虑引入分布式文件系统。
分布式存储系统,是将数据分散存储在多台服务器上,利用多台服务器分担存储负荷以及网络流量,它不但提高了系统的可靠性、可用性和存取效率,还易于扩展。
目前商用的文件存储服务有很多,比如阿里云 OSS、腾讯云、华为云等等,对于许多中小型企业来说,如果不考虑上云,或者为了节约成本,也可以选择开源的分布式存储中间件自行部署,例如 FastDfs,HDFS, MinIO 等。
MinIO
MinIO offers high-performance, S3 compatible object storage. Native to Kubernetes, MinIO is the only object storage suite available on every public cloud, every Kubernetes distribution, the private cloud and the edge. MinIO is software-defined and is 100% open source under GNU AGPL v3.
在MinIO 官网,介绍其能提供高性能、S3 兼容的对象存储。是 Kubernetes 的原生产品,是唯一一个可在每个公共云、每个 Kubernetes 发行版、私有云和边缘上使用的对象存储套件。MinIO 是软件定义的,在 GNU AGPL v3 下是 100%开源的。
安装
独立安装
独立的 MinIO 部署由具有一个或多个磁盘的单个 minio 服务器进程组成。独立部署最适合本地开发环境。
- 安装 minio server
linux 环境下, 64-bit Intel
curl https://dl.minio.org.cn/server/minio/release/linux-amd64/minio \ --create-dirs \ -o $HOME/minio-binaries/minio chmod +x $HOME/minio-binaries/minio export PATH=$PATH:$HOME/minio-binaries/ minio --help
64-bit PPC
curl https://dl.minio.org.cn/server/minio/release/linux-ppc64le/minio \ --create-dirs \ -o $HOME/minio-binaries/minio chmod +x $HOME/minio-binaries/minio export PATH=$PATH:$HOME/minio-binaries/ minio --help
- 添加 TLS/SSL 证书(可选)
通过指定 MinIO 证书目录的私钥 (.key) 和公共证书 (.crt), 启用与 MinIO 服务器的 TLS/SSL 连接:
- 对于 Linux/MacOS:${HOME}/.minio/certs
- 对于 Windows:%%USERPROFILE%%.minio\certs
如果 MinIO 服务器在证书目录中检测到所需的证书,则会自动启用 TLS/SSL 连接。
- 启动 minio server
按照以下命令启动服务器, 以下示例是假定当前主机至少有四个磁盘。
export MINIO_ROOT_USER=minio-admin export MINIO_ROOT_PASSWORD=minio-secret-key-CHANGE-ME export MINIO_KMS_SECRET_KEY=my-minio-encryption-key:bXltaW5pb2VuY3J5cHRpb25rZXljaGFuZ2VtZTEyMwo= minio server /mnt/disk{1...4}/data
- 连接到 minio server
使用 MinIO Client (mc) 命令从本机连接到运行 minio 服务器的主机。
mc alias set mylocalminio 192.0.2.10:9000 minioadmin minio-secret-key-CHANGE-ME
ip 和端口需要替换为实际环境变量。
最终可以登录 admin 管理后台管理文件:
集群安装
集群环境的安装方式可以参考官网文档: 集群安装
Springboot 集成 minio
1.maven 导入依赖
在项目的 pom.xml 添加依赖
<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.3.0</version> </dependency>
2.配置参数
在 application-*.yml 文件中添加 minio 配置参数。
minio: endpoint: https://xxx.com accessKey: admin secretKey: admin upload-expiry: 432000
3.读取连接参数
新建 Minio 配置类,实例化 MinioClient。
@Configuration @ConfigurationProperties("spring.minio") @Data public class MinioConfig { private String endpoint; private String accessKey; private String secretKey; private int uploadExpiry; @Bean public MinioClient minioClient(){ return MinioClient.builder() .endpoint(this.getEndpoint()) .credentials(this.getAccessKey(),this.getSecretKey()) .build(); } }
4.生成加签 URL, 供前端上传文件
前端页面上传文件时,首先提供要上传的文件信息,调用接口生成预置上传文件地址。
private String generatePresignedUploadUrl(String bucketName, String filePath, Map<String, String> extendData) { HashMap<String, String> extraHeaders = new HashMap<>(); extraHeaders.put("Content-Type", "application/octet-stream"); extraHeaders.put("Content-Disposition", "attachment"); try { String url = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() .method(Method.PUT) .bucket(bucketName) .object(filePath) .extraHeaders(extraHeaders) .expiry(minioConfig.getUploadExpiry()) .extraQueryParams(extendData) .build() ); return url; } catch (Exception e) { throw new RuntimeException(e); } }
5.生成下载文件地址
private String getPresignedDownloadUrl(String bucketName, String storageFullPath) { //生成url try { String url = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(bucketName) .object(storageFullPath) .expiry(minioConfig.getUploadExpiry()) .build() ); return url; } catch (Exception e) { log.error("获取加签URL出错:{}", e.getMessage()); throw new RuntimeException(e); } }
6.前端根据上传文件地址直传文件
<script type="text/javascript"> $(function () { // 地址通过上文接口方法获取 var putFileUrl = "https://xxx.com/1.png?respongse-content-type**"; // 提交 $("#uploadForm").on("submit", function (event) { // this为当前form对象 var form = this; $.ajax({ url: putFileUrl, type: "put", // 文件对象 data: $('#file')[0].files[0], dataType: "JSON", // 异步 async: true, processData: false, contentType: false, error: function (xhr, status, error) { alert("上传失败!"); }, success: function (result) { alert("上传成功!"); }, }); return false; }); }); </script>
7.上传下载效果展示
获取上传文件地址
获取下载地址
小结
本文简单介绍了 minio 的安装,以及 java 对 minio 的使用方法。后续会进一步针对 minio 的存储机制、多租户机制的实现原理做详细介绍,敬请期待!