Minio存储系统&SpringBoot整合Minio

860 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

Minio存储系统&SpringBoot整合Minio

前言:假如要对系统文件进行存储的话,可以有几种选择:第三方的oss(Object Storage Service)服务,如阿里oss、七牛oss、腾讯等以及自己搭建S3文件服务(minio、FastDFS )。使用第三方系统进行文件存储的好处是便捷、拿来即用且无运维成本。但当涉及敏感文件时,使用第三方文件服务就会有数据泄露的问题,毕竟数据是在第三方公司服务器上。基于这样的场景,我们就得搭建私有云对象存储服务。

1、Minio官方介绍

MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。

MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。

MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。

在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品

知识补充:

什么是S3:Simple Storage Service即简单存储服务,是亚马逊于2006年推出的(Amazon S3 ),此后新老厂商一窝蜂地推出各种产品,形态各异,但都号称对象存储。亚马逊没有给出一个定义,也没有看到有业界普通接受的说法。Amazon S3是⼀个公开的云存储服务,Web 应⽤程序开发⼈员可以使⽤它存储数字资产,包括图⽚、视频、⾳乐和⽂档。S3 提供⼀个 RESTful API 以编程⽅式实现与该服务的交互。Amazon 是最早的对象存储服务厂商,制定文件存储相关的业内标准,即S3协议(Minio 支持s3协议)。

通过 S3 存储和检索的资产被称为对象。对象存储在存储段(bucket) 中。您可以用硬盘进行类比:对象就像是文件,存储段就像是文件夹(或目录)。与硬盘一样,对象和存储段也可以通过统一资源标识符(Uniform Resource Identifier,URI)查找。

1.1、MINIO的基础概念

  • Object:存储到Minio的基本对象,如文件、字节流等
  • Bucket:用来存储Object的逻辑空间。每个Bucket之间的数据是相互隔离的。对于客户端而言,就相当于一个存储文件的顶层文件夹。
  • Drive:即存储数据的磁盘,在MinIO启动时,以参数的方式传入。Minio中所有的对象都会存储在Drive里
  • Set:即一组Drive的集合,分布式部署根据集群规模自动划分一个或多个Set,每个Set的Drive分布在不同的位置。一个对象存储在一个Set上

1.2、纠删码EC(Erasure Code)

MinIO使用纠删码机制来保住高可靠性,使用highwayhash来处理数据损坏(Bit Rot Protection)。关于纠删码,简单来说就是可以通过数学计算,把丢失的数据进行还原,它可以将n份原始数据,增加m份数据,并能通过n+m份中的任意n份数据,还原为原始数据。即如果有任意小于等于m份的数据丢失。仍然能通过剩下的数据还原出来。其实就是纠删码将对象拆分为一半数据,一半是奇偶校验块,任意丢失一般磁盘都可以进行数据恢复。

image-20220529205908539.png

2、实验环境

3、minio安装

  • 拉取镜像
 docker pull minio/minio:RELEASE.2021-06-17T00-10-46Z.hotfix.35a0912ff
  • 创建容器
 # 普通部署
 docker run -p 9000:9000 -p 9001:9001 -d 
 --name minio 
 -v /opt/docker/minio/data:/data 
 -v /opt/docker/minio/config:/root/.minio 
 -e "MINIO_ROOT_USER=minio" 
 -e "MINIO_ROOT_PASSWORD=minio@12345" minio/minio server /data 
 --console-address ":9000" --address ":9001"
 ​
 # 纠错码模式部署(使用这个)
 docker run --name minio \
 -p 9000:9000 \
 -d \
 -e "MINIO_ACCESS_KEY=minio" \
 -e "MINIO_SECRET_KEY=minio@123456" \
 -v /opt/docker/minio/data1:/data1 \
 -v /opt/docker/minio/data2:/data2 \
 -v /opt/docker/minio/data3:/data3 \
 -v /opt/docker/minio/data4:/data4 \
 -v /opt/docker/minio/config:/root/.minio \
 minio/minio:RELEASE.2021-06-17T00-10-46Z.hotfix.35a0912ff \
 server /data1 /data2 /data3 /data4 
 ​

image-20220529192524625.png

image-20220529192831577.png

  • 现在的数据卷结构

image-20220529213338294.png

  • 创建bucket

    Buckets(水桶):MinIO 使用桶来组织对象。存储桶类似于文件系统中的文件夹或目录,其中每个存储桶可以保存任意数量的对象。

image-20220529213432559.png

  • 创建三个bucket

image-20220529213542631.png

  • 再次查看数据卷

image-20220529213609132.png

  • 在test-bucket1上传3个文件,再次查看数据卷

image-20220529215158871.png

  • 查看数据卷,可以看到每个drive(data1、data2...)里的bucket都备份了一份数据

image-20220529215144677.png

  • 查看里面存储的数据,可以看到,data1、data4是原数据,data2、data3是经过算法处理的。同时,若上传的文件大的话就会产生part1、part2...文件,分块存储

image-20220529215546574.png

3、Java整合minio

image-20220531220244931.png

3.1、与Spring集成的依赖

 <dependency>
     <groupId>org.jetbrains.kotlin</groupId>
     <artifactId>kotlin-stdlib</artifactId>
     <version>1.3.70</version>
 </dependency>
 ​
 <dependency>
     <groupId>io.minio</groupId>
     <artifactId>minio</artifactId>
     <version>8.4.1</version>
     <exclusions>
         <exclusion>
             <groupId>org.jetbrains.kotlin</groupId>
             <artifactId>kotlin-stdlib</artifactId>
         </exclusion>
     </exclusions>
 </dependency>

3.2、控制台例子

  • 基础操作,详细请看代码。更多的操作请看官方例子
  • 代码位置:ppz.minio.minio.demo.ConsoleDemo
 // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
 MinioClient minioClient =
         MinioClient.builder()
                 .endpoint("http://192.168.138.130:9000")
                 .credentials("minio", "minio@123456")
                 .build();
 ​
 // 获取桶列表
 List<Bucket> bucketList = minioClient.listBuckets();
 for (Bucket bucket : bucketList) {
     System.out.println(bucket.creationDate() + ", " + bucket.name());
 }
 ​
 // 判断桶bucket3是否存在,不存在则新建
 boolean found =
         minioClient.bucketExists(BucketExistsArgs.builder().bucket("bucket3").build());
 if (!found) {
     minioClient.makeBucket(MakeBucketArgs.builder().bucket("bucket3").build());
 } else {
     System.out.println("Bucket 'bucket3' already exists.");
 }
 ​
 // 上传文件 默认情况下,如果已存在同名Object且对该Object有访问权限,则新添加的Object将覆盖原有的Object,并返回200 OK
 {
     // Upload 'my-filename' as object 'my-objectname' in 'my-bucketname'.
     ObjectWriteResponse uploadResponse = minioClient.uploadObject(
             UploadObjectArgs.builder()
                     .bucket("bucket3")
                     .object("test-object.jpg")
                     .filename("test.jpg")
                     .contentType("image/jpeg")
                     .build());
     System.out.println("test.jpg is uploaded to bucket3 successfully");
 }
 ​
 // 获取文件url,该url一天后过期
 {
     String url =
             minioClient.getPresignedObjectUrl(
                     GetPresignedObjectUrlArgs.builder()
                             .method(Method.GET)
                             .bucket("bucket3")
                             .object("test.jpg")
                             .expiry(60 * 60 * 24)
                             .build());
     System.out.println("url:"+url);
 }
 ​
 // 下载文件
 {
     String downloadPath = "D:\test-object.jpg";
     minioClient.downloadObject(
             DownloadObjectArgs.builder()
                     .bucket("bucket3")
                     .object("test-object.jpg")
                     .filename(downloadPath)
                     .build());
     System.out.println("test-object.jpg is successfully downloaded to " + downloadPath);
 }
 ​
 // 删除文件
 {
     minioClient.removeObject(
             RemoveObjectArgs.builder().bucket("bucket3").object("test-object.jpg")
             .build());
     System.out.println("remove test-object.jpg successfully");
 }

image-20220531220636620.png

image-20220531231809914.png

image-20220531230901827.png

3.2、SpringBoot整合Minio-sdk

  • 其实都差不多的,具体看官网例子套进去就好
 @Configuration
 @EnableConfigurationProperties(MinioProperties.class)
 public class MinioConfig {
     @Autowired
     private MinioProperties minioProperties;
 ​
     @Bean
     public MinioClient minioClient(){
         return MinioClient.builder()
                 .endpoint(minioProperties.getEndpoint())
                 .credentials(minioProperties.getAccessKey(),minioProperties.getSecretKey())
                 .build();
     }
 }
 @Service
 public class MinioService {
 ​
     @Autowired
     private MinioClient minioClient;
 ​
     public String getUrl(String bucket, String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
         String url =
                 minioClient.getPresignedObjectUrl(
                         GetPresignedObjectUrlArgs.builder()
                                 .method(Method.GET)
                                 .bucket(bucket)
                                 .object(objectName)
                                 .expiry(60 * 60 * 24)
                                 .build());
         return url;
     }
 ​
     /**
      * 创建bucket
      */
     public void createBucket(String bucketName) throws Exception {
         if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
             minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
         }
     }
 ​
     // ...
 ​
 }

3.3、码云地址

gitee.com/pzxbilibili…

4、坑爹:

image-20220531154944518.png

  • minio迭代非常快第一次部署时用的是lastest的,即RELEASE.2022-05-08T23-50-31Z.hotfix.a8c39d7cb
  • 连接本地api时一直报SignatureDoesNotMatch等错误,然后最新的jar包是和springboot的包有冲突,然后换了旧版之后就没问题了,坑都给踩平了,请放心食用

参考资料