SpringBoot 搭建基于 minio 的高性能存储服务
Posted 芋道源码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 搭建基于 minio 的高性能存储服务相关的知识,希望对你有一定的参考价值。
点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 10:33 更新文章,每天掉亿点点头发...
源码精品专栏
原创 | Java 2021 超神之路,很肝~
中文详细注释的开源项目
RPC 框架 Dubbo 源码解析
网络应用框架 Netty 源码解析
消息中间件 RocketMQ 源码解析
数据库中间件 Sharding-JDBC 和 MyCAT 源码解析
作业调度中间件 Elastic-Job 源码解析
分布式事务中间件 TCC-Transaction 源码解析
Eureka 和 Hystrix 源码解析
Java 并发源码
来源:blog.csdn.net/weixin_45089791/
article/details/116921075/
什么是minio
引用官网:
MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储。它与Amazon S3云存储服务兼容。使用MinIO构建用于机器学习,分析和应用程序数据工作负载的高性能基础架构。
官网地址:
https://min.io/
文档地址:
https://docs.min.io/
一. 使用docker 搭建minio 服务。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。
项目地址:https://github.com/YunaiV/ruoyi-vue-pro
GNU / Linux和macOS
docker run -p 9000:9000 \\
--name minio1 \\
-v /mnt/data:/data \\
-e "MINIO_ROOT_USER=AKIAiosFODNN7EXAMPLE" \\
-e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \\
minio/minio server /data
windows
docker run -p 9000:9000 \\
--name minio1 \\
-v D:\\data:/data \\
-e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \\
-e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \\
minio/minio server /data
MINIO_ROOT_USER
:为用户keyMINIO_ROOT_PASSWORD
:为用户密钥以上搭建的都是单机版的。想要了解分布式 的方式请查看官网文档。
这就是在win的docker上运行的。
当启动后在浏览器访问http://localhost:9000
就可以访问minio的图形化界面了,如图所示:
二. 下面开始搭建springboot 环境基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。
项目地址:https://github.com/YunaiV/onemall
初始化一个springboot项目大家都会,这里不多做介绍。
主要是介绍需要引入的依赖:
<!-- thymeleaf模板渲染引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 操作minio的java客户端-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
<!-- lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
依赖可以官方文档里找:https://docs.min.io/docs/java-client-quickstart-guide.html
下面介绍配置文件:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
#minio配置
minio:
access-key: AKIAIOSFODNN7EXAMPLE #key就是docker初始化是设置的,密钥相同
secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
url: http://localhost:9000
bucket-name: wdhcr
thymeleaf:
cache: false
创建minio的配置类:
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
@Data
public class MinioConfiguration
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();
使用配置属性绑定进行参数绑定,并初始化一个minio client对象放入容器中。
下面就是我封装的minio client 操作minio的简单方法的组件。
@Component
public class MinioComp
@Autowired
private MinioClient minioClient;
@Autowired
private MinioConfiguration configuration;
/**
* @description: 获取上传临时签名
* @dateTime: 2021/5/13 14:12
*/
public Map getPolicy(String fileName, ZonedDateTime time)
PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
postPolicy.addEqualsCondition("key", fileName);
try
Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
HashMap<String, String> map1 = new HashMap<>();
map.forEach((k,v)->
map1.put(k.replaceAll("-",""),v);
);
map1.put("host",configuration.getUrl()+"/"+configuration.getBucketName());
return map1;
catch (ErrorResponseException e)
e.printStackTrace();
catch (InsufficientDataException e)
e.printStackTrace();
catch (InternalException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (InvalidResponseException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (ServerException e)
e.printStackTrace();
catch (XmlParserException e)
e.printStackTrace();
return null;
/**
* @description: 获取上传文件的url
* @dateTime: 2021/5/13 14:15
*/
public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit)
try
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(method)
.bucket(configuration.getBucketName())
.object(objectName)
.expiry(time, timeUnit).build());
catch (ErrorResponseException e)
e.printStackTrace();
catch (InsufficientDataException e)
e.printStackTrace();
catch (InternalException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (InvalidResponseException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (XmlParserException e)
e.printStackTrace();
catch (ServerException e)
e.printStackTrace();
return null;
/**
* @description: 上传文件
* @dateTime: 2021/5/13 14:17
*/
public void upload(MultipartFile file, String fileName)
// 使用putObject上传一个文件到存储桶中。
try
InputStream inputStream = file.getInputStream();
minioClient.putObject(PutObjectArgs.builder()
.bucket(configuration.getBucketName())
.object(fileName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build());
catch (ErrorResponseException e)
e.printStackTrace();
catch (InsufficientDataException e)
e.printStackTrace();
catch (InternalException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (InvalidResponseException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (ServerException e)
e.printStackTrace();
catch (XmlParserException e)
e.printStackTrace();
/**
* @description: 根据filename获取文件访问地址
* @dateTime: 2021/5/17 11:28
*/
public String getUrl(String objectName, int time, TimeUnit timeUnit)
String url = null;
try
url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(configuration.getBucketName())
.object(objectName)
.expiry(time, timeUnit).build());
catch (ErrorResponseException e)
e.printStackTrace();
catch (InsufficientDataException e)
e.printStackTrace();
catch (InternalException e)
e.printStackTrace();
catch (InvalidKeyException e)
e.printStackTrace();
catch (InvalidResponseException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (XmlParserException e)
e.printStackTrace();
catch (ServerException e)
e.printStackTrace();
return url;
简单说明:
下面展示页面html,使用的是VUE+element-ui进行渲染。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<title>上传图片</title>
</head>
<body>
<div id="app">
<el-row :gutter="2">
<el-col :span="8">
<div class="div-center-class">
<div class="">
<center><h3>传统上传</h3></center>
<el-upload
class="upload-demo"
action="#"
drag
:http-request="uploadHandle">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<div v-if="imgUrl">
<img :src="imgUrl" style="width: 40px;height: 40px"></img>
</div>
</div>
</div>
</el-col>
<el-col :span="8">
<div class="div-center-class">
<div class="">
<center><h3>前端formData直传</h3></center>
<el-upload
class="upload-demo"
action="#"
drag
:http-request="httpRequestHandle">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<div v-if="directUrl">
<img :src="directUrl" style="width: 40px;height: 40px"></img>
</div>
</div>
</div>
</el-col>
<el-col :span="8">
<div class="div-center-class">
<div class="">
<center><h3>前端Url直传</h3></center>
<el-upload
class="upload-demo"
action="#"
drag
:http-request="UrlUploadHandle">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<div v-if="uploadUrl">
<img :src="uploadUrl" style="width: 40px;height: 40px"></img>
</div>
</div>
</div>
</el-col>
</el-row>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- import javascript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!--import axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue(
el: \'#app\',
data: function ()
return
imgUrl: \'\',
directUrl: \'\',
uploadUrl: \'\'
,
methods:
uploadHandle(options)
let file = options;
this.traditionPost(file);
,
traditionPost(file)
_that = this
const form = new FormData();
form.append("fileName", file.name);
form.append("file", file);
this.axiosPost("post", "/upload", form).then(function (res)
if (res.status === 200)
_that.imgUrl = res.data.data
else
alert("上传失败!")
)
,
getpolicy(file)
_that = this
axios.get(\'policy?fileName=\' + file.name)
.then(function (response)
let xamzalgorithm, xamzcredential, policy, xamzsignature, xamzdate, host = response.data.data;
let formData = new FormData();
formData.append("key", file.name);
formData.append("x-amz-algorithm", xamzalgorithm); // 让服务端返回200,不设置则默认返回204。
formData.append("x-amz-credential", xamzcredential);
formData.append("policy", policy);
formData.append("x-amz-signature", xamzsignature);
formData.append("x-amz-date", xamzdate);
formData.append("file", file);
// 发送 POST 请求
_that.axiosPost("post", host, formData).then(function (res)
if (res.status === 204)
axios.get(\'url?fileName=\' + file.name).then(function (res)
_that.directUrl = res.data.data;
)
else
alert("上传失败!")
)
)
,
httpRequestHandle(options)
let file = options;
this.getpolicy(file);
,
UrlUploadHandle(options)
let file = options;
this.getUploadUrl(file);
,
getUploadUrl(file)
_that = this
console.log(file)
axios.get(\'uploadUrl?fileName=\' + file.name)
.then(function (response)
let url = response.data.data;
// 发送 put 请求
let config = \'Content-Type\': file.type
_that.axiosPost("put", url, file, config).then(function (res)
if (res.status === 200)
axios.get(\'url?fileName=\' + file.name).then(function (res)
_that.uploadUrl = res.data.data;
)
else
alert("上传失败!")
)
)
,
//封装
//axios封装post请求
axiosPost(method, url, data, config)
let result = axios(
method: method,
url: url,
data: data,
headers: config
).then(resp =>
return resp
).catch(error =>
return "exception=" + error;
);
return result;
)
</script>
<style>
.div-center-class
padding: 28% 0%;
text-align: center;
background: beige;
</style>
</html>
页面效果
可以分别体验不同的实现效果。
以上就是使用springboot搭建基于minio的高性能存储服务的全部步骤了。
项目地址是:
https://gitee.com/jack_whh/minio-upload
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
minio笔记3--基于k8s搭建minio集群
minio笔记3--基于k8s搭建minio集群
- 介绍
- 安装单个节点
- 安装 minio 集群
- 注意事项
- 说明
介绍
笔者在 minio笔记01–部署与测试minio 和 minio笔记02–基于swarm搭建minio集群 中介绍了minio 的集群搭建步骤和基础使用方法,本文继上述两篇文章介绍k8s下的minio搭建过程。其实很早就准备写一份基于k8s的集群搭建方式,但是由于各种原因耽搁很久了,最近再次发了些时间完成了k8s下的minio部署,将步骤分享在此处以供有需要的小伙伴们学习!
后续也会在此处继续更新 k8s下minio的部署和常见注意事项!
安装单个节点
- 部署服务
1. 添加 helm 源
helm repo add minio https://helm.min.io/
2. 下载chart压缩包
helm fetch minio/minio
3. 解压并按需更改values.yaml
tar zxvf minio-8.0.10.tgz
vim values.yaml
resources:
requests:
memory: 256Mi
4. 部署实例
helm install minio \\
--namespace minio \\
--create-namespace \\
--set accessKey=minio,secretKey=minio123 \\
--set mode=standalone \\
--set service.type=NodePort \\
--set persistence.enabled=false \\
--set persistence.size=10Gi \\
- 测试
集群deployment 和 svc - web 界面:
安装 minio 集群
- 部署服务
1. 添加 helm 源
helm repo add minio https://helm.min.io/
2. 下载chart压缩包
helm fetch minio/minio
3. 解压并按需更改values.yaml
tar zxvf minio-8.0.10.tgz
vim values.yaml
resources:
requests:
memory: 256Mi
4. 部署实例
helm install minio \\
--namespace minio --create-namespace \\
--set accessKey=minio,secretKey=minio123 \\
--set mode=distributed \\
--set replicas=4 \\
--set service.type=NodePort \\
--set persistence.enabled=false \\
--set persistence.size=10Gi \\
- 测试
集群statefulset、svc 和 endpoints
kubectl -n minio get statefulset,svc,endpoints minio - web 界面:
新建bucket test01,test02,并各自上传一个文件 - mc 命令查看集群信息
mc alias set local http://192.168.2.131:32000 minio minio123
mc ls local 查看文件信息 - mc admin info local 查看集群信息
- 由此可见,已经部署了一个4节点的minio集群。
注意事项
- 本文主要是用于测试,由此使用容器的临时存储,如果在生产上使用者需要指定动态存储类,可以使用 nfs、longhorn、ceph 等持久化存储。
更多持久化存储见:k8s storage-classes 笔者新建nfs-client 存储类后,通过nfs动态分配存储空间,从而实现了minio 的持久化存储。
helm install minio \\
--namespace minio --create-namespace \\
--set accessKey=minio,secretKey=minio123 \\
--set mode=distributed \\
--set replicas=4 \\
--set service.type=NodePort \\
--set persistence.enabled=true \\
--set persistence.size=500Mi \\
--set persistence.storageClass=nfs-client \\
minio-8.0.10/minio
存储路径如下:
/data/nfs$ ls
说明
- 软件环境
k8s 版本: 1.19.4
helm chart 版本: minio/minio:minio-8.0.10
minio镜像版本:minio/minio:RELEASE.2021-02-14T04-01-33Z - 参考文档
1 minio 高性能 Kubernetes 原生对象存储2 kubernetes部署minio对象存储3 minio 官方文档4 k8s中创建nfs存储类(公共盘)
以上是关于SpringBoot 搭建基于 minio 的高性能存储服务的主要内容,如果未能解决你的问题,请参考以下文章