对象存储服务MinIO
|字数总计:2.9k|阅读时长:13分钟|阅读量:
一.MinIo基本介绍
1.简介
MinIO基于Apache License v2.0开源协议的对象存储服务,可以做为云存储的解决方案用来保存海量的图片,视频,文档。由于采用Golang实现,服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置简单,基本是复制可执行程序,单行命令可以运行起来。MinIO兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
S3 ( Simple Storage Service简单存储服务)
基本概念
- bucket – 类比于文件系统的目录
- Object – 类比文件系统的文件
- Keys – 类比文件名
官网文档:http://docs.minio.org.cn/docs/
2.特点
数据保护
Minio使用Minio Erasure Code(纠删码)来防止硬件故障。即便损坏一半以上的driver,但是仍然可以从中恢复。
高性能
作为高性能对象存储,在标准硬件条件下它能达到55GB/s的读、35GB/s的写速率
可扩容
不同MinIO集群可以组成联邦,并形成一个全局的命名空间,并跨越多个数据中心
SDK支持
基于Minio轻量的特点,它得到类似Java、Python或Go等语言的sdk支持
有操作页面
面向用户友好的简单操作界面,非常方便的管理Bucket及里面的文件资源
功能简单
这一设计原则让MinIO不容易出错、更快启动
丰富的API
支持文件资源的分享连接及分享链接的过期策略、存储桶操作、文件列表访问及文件上传下载的基本功能等。
文件变化主动通知
存储桶(Bucket)如果发生改变,比如上传对象和删除对象,可以使用存储桶事件通知机制进行监控,并通过以下方式发布出去:AMQP、MQTT、Elasticsearch、Redis、NATS、MySQL、Kafka、Webhooks等。
3.对象存储方式比较
存储方式 |
优点 |
缺点 |
服务器磁盘 |
开发便捷,成本低 |
扩展困难 |
分布式文件系统 (如MinIo) |
容易实现扩容 |
复杂度高 |
第三方存储 (如阿里OSS) |
开发简单,功能强大,免维护 |
收费 |
4.分布式文件系统比较
存储方式 |
优点 |
缺点 |
FastDFS |
1,主备服务,高可用 2,支持主从文件,支持自定义扩展名 3,支持动态扩容 |
1,没有完备官方文档,近几年没有更新 2,环境搭建较为麻烦 |
MinIO |
1,性能高,准硬件条件下它能达到55GB/s的读、35GB/s的写速率 2,部署自带管理界面 3,MinIO.Inc运营的开源项目,社区活跃度高 4,提供了所有主流开发语言的SDK |
1,不支持动态增加节点 |
二.MinIo安装教程
使用Docker的方式安装MInIo,Docker使用教程 https://qingling.icu/posts/19306.html
1 2 3 4 5 6
| #拉取minio的镜像 docker pull minio/minio #创建并运行容器 #设置用户名-e "MINIO_ACCESS_KEY=minio" #设置密码 -e "MINIO_SECRET_KEY=minio123" docker run -p 9000:9000 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data
|
访问: http://192.168.200.130:9000
Access Key为minio Secret_key 为minio123 进入系统后可以看到主界面
三.快速入门
基本概念
- bucket – 类比于文件系统的目录
- Object – 类比文件系统的文件
- Keys – 类比文件名
1.创建一个bucket
点击右下角的“+”号 ,创建一个桶
创建成功后
2.环境搭建
2.1 创建一个Demo工程
2.2 导入依赖和创建启动类
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependencies> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
|
启动类
1 2 3 4 5 6 7 8 9 10 11 12
| package com.heima.minio;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class MinIOApplication {
public static void main(String[] args) { SpringApplication.run(MinIOApplication.class,args); } }
|
3.测试案例
3.1 上传文件进行静态访问
目标:把test.html文件上传到minio中,并且可以在浏览器中访问
test.html测试文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <b>普通文本 String 展示:</b><br><br> Hello freemarker <br> <hr> <b>对象Student中的数据展示:</b><br/> 姓名:小明<br/> 年龄:18 <hr> </body> </html>
|
文件上传代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.heima.minio;
@SpringBootTest(classes = MinIOApplication.class) @RunWith(SpringRunner.class) @Slf4j public class MinIOTest {
@Test public void testMinIO(){ try { FileInputStream inputStream = new FileInputStream("C:\\Gong\\data\\test.html"); MinioClient minioClient = MinioClient.builder() .credentials("minio", "minio123") .endpoint("http://192.168.200.130:9000") .build(); PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object("test.html") .contentType("text/html") .bucket("leadnews") .stream(inputStream,inputStream.available(),-1) .build(); log.info("http://192.168.200.130:9000/leadnews/test.html"); minioClient.putObject(putObjectArgs); } catch (Exception e) { e.printStackTrace(); } }
}
|
执行成功之后可以在MinIO中找到该文件
设置浏览器输入文件在minio中的地址可以直接访问文件的内容
设置bucket的访问权限
设置完毕后访问文件的地址可以直接访问到
4.封装MinIO为Starter-以黑马头条项目为例
黑马头条项目gitee地址: https://gitee.com/JasonsGong/heima-leadnews
在开发的过程中,有很多模块需要使用到文件服务,我们直接把文件服务封装成一个Starter,方便其余的模块调用
4.1 创建模块heima-file-starter
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>7.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
|
4.2 配置类
MinIOConfigProperties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.heima.file.config;
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties;
import java.io.Serializable;
@Data @ConfigurationProperties(prefix = "minio") public class MinIOConfigProperties implements Serializable {
private String accessKey; private String secretKey; private String bucket; private String endpoint; private String readPath; }
|
MinIOConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.heima.file.config;
import com.heima.file.service.FileStorageService; import io.minio.MinioClient; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Data @Configuration @EnableConfigurationProperties({MinIOConfigProperties.class})
@ConditionalOnClass(FileStorageService.class) public class MinIOConfig {
@Autowired private MinIOConfigProperties minIOConfigProperties;
@Bean public MinioClient buildMinioClient(){ return MinioClient .builder() .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey()) .endpoint(minIOConfigProperties.getEndpoint()) .build(); } }
|
4.3 封装操作minIO类
FileStorageService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.heima.file.service;
import java.io.InputStream;
public interface FileStorageService {
public String uploadImgFile(String prefix, String filename,InputStream inputStream);
public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);
public void delete(String pathUrl);
public byte[] downLoadFile(String pathUrl);
}
|
MinIOFileStorageService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| package com.heima.file.service.impl;
import com.heima.file.config.MinIOConfig; import com.heima.file.config.MinIOConfigProperties; import com.heima.file.service.FileStorageService; import io.minio.GetObjectArgs; import io.minio.MinioClient; import io.minio.PutObjectArgs; import io.minio.RemoveObjectArgs; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Date;
@Slf4j @EnableConfigurationProperties(MinIOConfigProperties.class) @Import(MinIOConfig.class) public class MinIOFileStorageService implements FileStorageService {
@Autowired private MinioClient minioClient;
@Autowired private MinIOConfigProperties minIOConfigProperties;
private final static String separator = "/";
public String builderFilePath(String dirPath,String filename) { StringBuilder stringBuilder = new StringBuilder(50); if(!StringUtils.isEmpty(dirPath)){ stringBuilder.append(dirPath).append(separator); } SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); String todayStr = sdf.format(new Date()); stringBuilder.append(todayStr).append(separator); stringBuilder.append(filename); return stringBuilder.toString(); }
@Override public String uploadImgFile(String prefix, String filename,InputStream inputStream) { String filePath = builderFilePath(prefix, filename); try { PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object(filePath) .contentType("image/jpg") .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1) .build(); minioClient.putObject(putObjectArgs); StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath()); urlPath.append(separator+minIOConfigProperties.getBucket()); urlPath.append(separator); urlPath.append(filePath); return urlPath.toString(); }catch (Exception ex){ log.error("minio put file error.",ex); throw new RuntimeException("上传文件失败"); } }
@Override public String uploadHtmlFile(String prefix, String filename,InputStream inputStream) { String filePath = builderFilePath(prefix, filename); try { PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object(filePath) .contentType("text/html") .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1) .build(); minioClient.putObject(putObjectArgs); StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath()); urlPath.append(separator+minIOConfigProperties.getBucket()); urlPath.append(separator); urlPath.append(filePath); return urlPath.toString(); }catch (Exception ex){ log.error("minio put file error.",ex); ex.printStackTrace(); throw new RuntimeException("上传文件失败"); } }
@Override public void delete(String pathUrl) { String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/",""); int index = key.indexOf(separator); String bucket = key.substring(0,index); String filePath = key.substring(index+1); RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build(); try { minioClient.removeObject(removeObjectArgs); } catch (Exception e) { log.error("minio remove file error. pathUrl:{}",pathUrl); e.printStackTrace(); } }
@Override public byte[] downLoadFile(String pathUrl) { String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/",""); int index = key.indexOf(separator); String bucket = key.substring(0,index); String filePath = key.substring(index+1); InputStream inputStream = null; try { inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build()); } catch (Exception e) { log.error("minio down file error. pathUrl:{}",pathUrl); e.printStackTrace(); }
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buff = new byte[100]; int rc = 0; while (true) { try { if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break; } catch (IOException e) { e.printStackTrace(); } byteArrayOutputStream.write(buff, 0, rc); } return byteArrayOutputStream.toByteArray(); } }
|
4.4 对外加入自动配置
在resources中新建META-INF/spring.factories
1 2
| org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.heima.file.service.impl.MinIOFileStorageService
|
4.5 其他微服务使用
第一,导入heima-file-starter的依赖
1 2 3 4 5
| <dependency> <groupId>com.heima</groupId> <artifactId>heima-file-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
|
第二,在微服务中添加minio所需要的配置
1 2 3 4 5 6
| minio: accessKey: minio secretKey: minio123 bucket: leadnews endpoint: http://192.168.200.130:9000 readPath: http://192.168.200.130:9000
|
第三,在对应使用的业务类中注入FileStorageService,样例如下:
1 2
| @Autowired private FileStorageService fileStorageService;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.heima.minio;
@SpringBootTest(classes = MinIOApplication.class) @RunWith(SpringRunner.class) @Slf4j public class MinIOTest {
@Autowired private FileStorageService fileStorageService;
@Test public void testMinIOStarter(){ try { FileInputStream inputStream = new FileInputStream("C:\\Gong\\data\\test.html"); String s = fileStorageService.uploadHtmlFile("", "test,html", inputStream); log.info(s); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
|