目录
一、前言
二、对象存储(Object Storage)介绍
(1)对象存储的特点
(2)Minio 与对象存储
(3)对象存储其他存储方式的区别
(4)对象存储的应用场景
三、Minio基础介绍
(1)主要特性
(2)应用场景
(3)架构和部署
四、SringBoot集成MinIO实现切片上传
1. 引入依赖
2.配置MinIO相关配置信息
3. 配置 MinIO 客户端
4. 创建文件切片上传服务
5. 创建文件切片上传控制器
6.测试及说明
一、前言
在数字化时代,文件上传是众多应用不可或缺的一环。随着文件体积的增大和用户对上传速度的追求,传统的上传方式已难以满足需求。SpringBoot作为Java开发者的利器,结合Minio这一高性能对象存储解决方案,为我们提供了一种全新的文件上传体验——文件切片极速上传。
本文将带领读者深入探索SpringBoot与Minio的结合,通过文件切片技术,实现高效、稳定的文件上传。我们将从基础概念出发,逐步介绍这个文件切片上传系统,解锁上传速度的新境界。希望对正在研究文件存储的小伙伴们有所启发~
二、对象存储(Object Storage)介绍
首先简单介绍一下对象存储的相关概念~~~
对象存储是一种数据存储架构,它将数据作为对象进行管理,而不是传统的文件系统或块存储方式。每个对象通常包含数据本身、元数据和唯一标识符。对象存储适用于大规模数据存储和高并发访问场景,具有高扩展性、高可靠性和低成本的特点。
(1)对象存储的特点
-
高扩展性:
-
对象存储系统可以轻松扩展存储容量,通过增加存储节点来满足不断增长的数据需求。
-
-
高可靠性:
-
对象存储系统通常采用数据冗余和分布式存储技术,确保数据的高可用性和可靠性。即使部分节点故障,数据也不会丢失。
-
-
低成本:
-
对象存储采用廉价的存储介质(如硬盘),并通过数据压缩和去重技术减少存储空间的占用,从而降低存储成本。
-
-
丰富的元数据:
-
每个对象都包含丰富的元数据,可以用于描述数据的属性、访问权限等信息,方便数据的检索和管理。
-
-
RESTful API:
-
对象存储系统通常提供 RESTful API,方便开发者通过 HTTP 协议进行数据的上传、下载和管理。
-
(2)Minio 与对象存储
Minio 是一个典型的对象存储解决方案,它完全兼容 Amazon S3 API,提供了以下对象存储的核心功能:
-
对象管理:
-
Minio 将数据作为对象进行管理,每个对象包含数据本身、元数据和唯一标识符。用户可以通过 S3 API 进行对象的创建、读取、更新和删除操作。
-
-
存储桶(Bucket):
-
存储桶是对象的容器,类似于文件系统中的目录。用户可以在 Minio 中创建和管理多个存储桶,每个存储桶可以包含多个对象。
-
-
访问控制:
-
Minio 支持基于存储桶和对象的访问控制,用户可以通过策略(Policy)和访问控制列表(ACL)来管理数据的访问权限。
-
-
数据冗余:
-
Minio 支持分布式部署,通过数据冗余技术确保数据的高可用性和可靠性。分布式 Minio 可以自动处理数据复制和故障恢复。
-
-
数据加密:
-
Minio 支持数据加密,包括服务器端加密和客户端加密,确保数据在传输和存储过程中的安全性。
-
-
RESTful API:
-
Minio 提供 RESTful API,方便开发者通过 HTTP 协议进行数据的管理和访问。
-
(3)对象存储其他存储方式的区别
对象存储(Object Storage)和普通存储(包括文件存储和块存储)是三种不同的数据存储架构,它们在数据管理方式、扩展性、性能和应用场景等方面存在显著差异。
存储方式 | 数据管理方式 | 扩展性 | 性能 | 应用场景 | 优点 | 缺点 |
---|---|---|---|---|---|---|
对象存储 | 数据作为对象进行管理,每个对象包含数据本身、元数据和唯一标识符。对象存储通常提供 RESTful API 进行数据访问和管理。 | 具有极高的扩展性,可以通过增加存储节点来扩展存储容量和提高性能。 | 适用于大规模数据访问和高并发场景,具有较高的吞吐量和较低的延迟。 | 适用于大规模数据存储和高并发访问场景,如静态网站托管、大数据处理、备份和归档、云原生应用等。 | 高扩展性:可以轻松扩展存储容量和性能; 高可靠性:通过数据冗余和分布式存储确保数据的高可用性和可靠性; 低成本:采用廉价的存储介质,并通过数据压缩和去重技术降低存储成本; 丰富的元数据:每个对象包含丰富的元数据,方便数据的检索和管理; RESTful API:提供 RESTful API,方便开发者进行数据访问和管理。 | 延迟较高:相对于块存储,对象存储的延迟较高,不适用于对延迟要求极高的应用场景。 复杂性:对象存储的架构和管理相对复杂,需要专业的技术团队进行维护。 |
文件存储 | 数据作为文件和目录层次结构进行管理,类似于传统的文件系统。文件存储通常提供文件路径进行数据访问。 | 扩展性有限,通常受限于单个服务器的存储容量和性能。 | 适用于中小规模数据访问,性能受限于单个服务器的处理能力。 | 适用于文件共享和协作场景,如企业文件服务器、网络附加存储(NAS)等。 | 简单易用:文件存储的架构和管理相对简单,易于使用和维护。 兼容性:兼容传统的文件系统操作,方便用户进行数据访问和管理。 | 扩展性有限:受限于单个服务器的存储容量和性能,难以扩展。 性能有限:性能受限于单个服务器的处理能力,不适用于高并发和大规模数据访问场景。 |
块存储 | 数据作为固定大小的块进行管理,每个块具有唯一的标识符。块存储通常作为虚拟机的存储卷使用,提供低延迟的数据访问。 | 扩展性一般,通常通过增加存储设备或扩展存储区域网络(SAN)来提高存储容量。 | 提供低延迟的数据访问,适用于对性能要求较高的应用场景,如数据库和虚拟机。 | 适用于对性能要求较高的应用场景,如数据库、虚拟化环境、高性能计算等。 | 低延迟:提供低延迟的数据访问,适用于对性能要求较高的应用场景。 高性能:适用于数据库、虚拟化环境等高性能计算场景。 | 扩展性有限:通常通过增加存储设备或扩展存储区域网络(SAN)来提高存储容量,扩展性有限。 成本较高:相对于对象存储,块存储的成本较高,特别是在大规模存储场景下。 |
(4)对象存储的应用场景
对象存储适用于多种应用场景,包括但不限于:
-
静态网站托管:对象存储可以作为静态网站的存储和分发平台,提供高速的内容传输。
-
大数据处理:对象存储可以作为大数据处理框架(如 Hadoop、Spark)的存储后端,提供高效的数据访问。
-
备份和归档:对象存储可以用于企业数据的备份和归档,确保数据的安全性和可恢复性。
-
云原生应用:对象存储与 Kubernetes 等容器编排平台无缝集成,适用于云原生应用的存储需求。
三、Minio基础介绍
Minio 是一个开源的高性能对象存储解决方案,专为云原生应用设计。它兼容 Amazon S3 API,提供了简单、可靠的存储服务,适用于各种规模的应用场景。Minio 的设计理念是轻量级和高性能,使其成为容器化和微服务架构中的理想选择。
(1)主要特性
-
兼容 S3 API:
-
Minio 完全兼容 Amazon S3 API,这意味着开发者可以使用现有的 S3 客户端和工具与 Minio 进行交互,无需修改代码。
-
-
分布式存储:
-
Minio 支持分布式部署,可以通过扩展节点来增加存储容量和提高性能。分布式 Minio 可以自动处理数据冗余和故障恢复,确保数据的高可用性和可靠性。
-
-
高性能:
-
Minio 采用 Go 语言编写,具有出色的性能和低延迟。它能够处理大规模的数据传输,适用于高并发场景。
-
-
数据安全:
-
Minio 支持数据加密(包括服务器端加密和客户端加密),确保数据在传输和存储过程中的安全性。
-
-
简单易用:
-
Minio 的安装和配置非常简单,支持多种操作系统和平台。它还提供了丰富的管理工具和 API,方便开发者进行管理和监控。
-
-
开源免费:
-
Minio 是开源项目,采用 Apache License 2.0 许可,用户可以免费使用并对其进行二次开发。
-
(2)应用场景
Minio 适用于多种应用场景,包括但不限于:
-
静态网站托管:Minio 可以作为静态网站的存储和分发平台,提供高速的内容传输。
-
大数据处理:Minio 可以作为大数据处理框架(如 Hadoop、Spark)的存储后端,提供高效的数据访问。
-
备份和归档:Minio 可以用于企业数据的备份和归档,确保数据的安全性和可恢复性。
-
云原生应用:Minio 与 Kubernetes 等容器编排平台无缝集成,适用于云原生应用的存储需求。
(3)架构和部署
Minio 支持单节点和分布式部署两种模式:
-
单节点部署:适用于小规模应用和开发测试环境。单节点 Minio 部署简单,易于管理。
-
分布式部署:适用于大规模应用和高可用性需求。分布式 Minio 通过多个节点组成存储集群,提供更高的性能和可靠性。
Minio 的部署可以通过 Docker 容器、Kubernetes 集群或直接在物理服务器上进行。它还提供了丰富的命令行工具和 Web 管理界面,方便用户进行配置和管理。这里主要介绍SpringBoot与minio的集成,因此这块笔者就不单独说明部署的详细方式了,仅采用容器化单实例服务进行。
#自定义账号密码运行容器
[root@node01 ~]# docker run -d \
> -p 9000:9000 \
> -p 9001:9001 \
> --name minio \
> -v /data/minio/data:/data \
> -e "MINIO_ROOT_USER=admin" \
> -e "MINIO_ROOT_PASSWORD=admin123" \
> swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/minio/minio:RELEASE.2024-06-13T22-53-53Z server /data --console-address ":9001"
Unable to find image 'swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/minio/minio:RELEASE.2024-06-13T22-53-53Z' locally
RELEASE.2024-06-13T22-53-53Z: Pulling from ddn-k8s/docker.io/minio/minio
d95a8f5a9b46: Pull complete
392be19a63f6: Pull complete
86f90f8ca150: Pull complete
7dc3c1e5f08a: Pull complete
1ab6ab2ba6f0: Pull complete
6fac698163eb: Pull complete
6a4e2f681031: Pull complete
53a5b322abdc: Pull complete
Digest: sha256:98fe67c08bf95945b34f8e74622976495e6c47b3e8dd2faed079ac2804b98c97
Status: Downloaded newer image for swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/minio/minio:RELEASE.2024-06-13T22-53-53Z
四、SringBoot集成MinIO实现切片上传
1. 引入依赖
首先,在你的 pom.xml
文件中引入必要的依赖,包括 minio
和其他相关依赖:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.7</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
2.配置MinIO相关配置信息
首先需要在MinIO服务页面配置一个令牌桶(Bucket),MinIO使用bucket来组织对象。bucket类似于文件系统中的文件夹或目录,其中每个bucket可以容纳任意数量的对象。这里咱们创建一个名为test的bucket。
-
versioning(版本控制):允许在同一键下保持同一对象的多个版本。
-
Object Locking(对象锁定):防止对象被删除。需要支持保留和合法持有。只能在创建桶时启用。
-
Quota(配额):限制bucket中的数据量。
-
Retention(存放):开启会施加规则,在一段时间内防止对象删除。为了设置桶保留策略,必须启用版本控制。
然后需要创建API的访问凭证,这个用于minio在springboot配置文件中使用时的配置。
完成后保留好access key和secret key信息。接下来可以在springboot的yml配置文件中配置minio的相关信息了:
server:
port: 8919
spring:
servlet:
multipart:
enabled: true
max-file-size: 2048MB
max-request-size: 2048MB
config:
file-server:
#文件服务,local/minio,local本地文件服务,minio minio服务
type: minio
local:
secret: e9eaa184ac1b4068829edb4f3ea978f4
# 防盗链st有效时长(秒)
st-effective-time: 300
file-dir: D:/springboot-test/uploadFile
preview-url: http://127.0.0.1:8918
minio:
access-key: ZTsent9wl6UlKBGiNoaD
secret-key: b1CXhMIovbevJ2q9LQuPR4lhaFNCqSlX2o5EgQtW
url: http://192.168.1.201:9000
bucket-name: test
-
access-key
和secret-key
是访问minio服务的凭证,就是上面刚创建的。 -
url是minio服务的地址,这里要区分web端的访问地址9001,默认9000是mino的服务地址。
-
bucket-name
是存储文件的桶名,这个咱们生成的名称是test。
3. 配置 MinIO 客户端
在你的 SpringBoot 应用中配置 MinIO 客户端。可以通过创建一个配置类来实现:
package com.yy.fs.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Minio 配置
*
* @author young
* @date 2024/09/03
*/
@Configuration
@Data
@ConfigurationProperties("config.file-server.minio")
public class MinioConfig {
private String accessKey;
private String secretKey;
private String url;
private String bucketName;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
}
4. 创建文件切片上传服务
创建一个服务类来处理文件切片上传的逻辑:
package com.yy.fs.mytest;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
@Service
public class FileUploadService {
private static final Logger LOGGER = LoggerFactory.getLogger(FileUploadService.class);
@Autowired
private MinioClient minioClient;
/*
* uploadChunk 用于上传文件块,参数包括桶名、对象名和文件块。
*/
public void uploadChunk(String bucketName, String objectName, MultipartFile chunkFile) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
// 检查指定的桶是否存在,如果不存在则创建一个新的桶。
boolean isExist =
minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!isExist) {
// Make a new bucket called bucket.
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} else {
LOGGER.info("Bucket " + bucketName + " already exists.");
}
byte[] bytes = chunkFile.getBytes();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
String suffix = objectName.contains(".") ? objectName.substring(objectName.lastIndexOf(".")):"";
// 使用MinIO客户端上传文件块到指定的桶和对象名
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName.substring(0,objectName.lastIndexOf(".")) + "_chunk" + suffix)
.stream(byteArrayInputStream, byteArrayInputStream.available(), -1)
.build()
);
}
}
5. 创建文件切片上传控制器
创建一个控制器来处理文件切片上传的请求,在实际项目中根据前端的参数传入即可:
package com.yy.fs.mytest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class FileUploadController {
@Autowired
private FileUploadService fileUploadService;
@PostMapping("/uploadChunk")
public String uploadChunk(
@RequestParam("bucketName") String bucketName,
@RequestParam("objectName") String objectName,
@RequestParam("chunkFile") MultipartFile chunkFile) {
try {
fileUploadService.uploadChunk(bucketName, objectName, chunkFile);
return "Chunk uploaded successfully";
} catch (Exception e) {
e.printStackTrace();
return "Failed to upload chunk ";
}
}
}
6.测试及说明
最后使用测试工具测试一下,这里咱们上传一个视频文件进行测试:
上传成功后可以在MinIO界面查看到已上传的视频信息:
并且支持下载,预览与分享,基本算一个文件存储系统类似的玩意。但是实际在服务存储的目录下就不同了:
data目录下随着我们创建一个test的桶而生成了一个test文件,当文件通过后端接口传入minio后根据文件大小自动被切片为了很多小文件,这也难怪他的文件上传速度要比直接上传整个文件高效多了。更主要的是可以省略去构建切片方法实现切片逻辑的步骤,让minio自己完成。感兴趣的小伙伴可参考下方链接继续研究一下~
参考地址:MinIO中文文档