文章很长,建议收藏起来,慢慢读! Java 高并发 发烧友社群:疯狂创客圈 奉上以下珍贵的学习资源:
-
免费赠送 经典图书:《Java高并发核心编程(卷1)》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
-
免费赠送 经典图书:《Java高并发核心编程(卷2)》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
-
免费赠送 经典图书:《Netty Zookeeper Redis 高并发实战》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
-
免费赠送 经典图书:《SpringCloud Nginx高并发核心编程》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
-
免费赠送 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元 加尼恩领取
推荐:入大厂 、做架构、大力提升Java 内功 的 精彩博文
入大厂 、做架构、大力提升Java 内功 必备的精彩博文 | 2021 秋招涨薪1W + 必备的精彩博文 |
---|---|
1:Redis 分布式锁 (图解-秒懂-史上最全) | 2:Zookeeper 分布式锁 (图解-秒懂-史上最全) |
3: Redis与MySQL双写一致性如何保证? (面试必备) | 4: 面试必备:秒杀超卖 解决方案 (史上最全) |
5:面试必备之:Reactor模式 | 6: 10分钟看懂, Java NIO 底层原理 |
7:TCP/IP(图解+秒懂+史上最全) | 8:Feign原理 (图解) |
9:DNS图解(秒懂 + 史上最全 + 高薪必备) | 10:CDN图解(秒懂 + 史上最全 + 高薪必备) |
11: 分布式事务( 图解 + 史上最全 + 吐血推荐 ) | 12:seata AT模式实战(图解+秒懂+史上最全) |
13:seata 源码解读(图解+秒懂+史上最全) | 14:seata TCC模式实战(图解+秒懂+史上最全) |
Java 面试题 30个专题 , 史上最全 , 面试必刷 | 阿里、京东、美团... 随意挑、横着走!!! |
---|---|
1: JVM面试题(史上最强、持续更新、吐血推荐) | 2:Java基础面试题(史上最全、持续更新、吐血推荐 |
3:架构设计面试题 (史上最全、持续更新、吐血推荐) | 4:设计模式面试题 (史上最全、持续更新、吐血推荐) |
17、分布式事务面试题 (史上最全、持续更新、吐血推荐) | 一致性协议 (史上最全) |
29、多线程面试题(史上最全) | 30、HR面经,过五关斩六将后,小心阴沟翻船! |
9.网络协议面试题(史上最全、持续更新、吐血推荐) | 更多专题, 请参见【 疯狂创客圈 高并发 总目录 】 |
SpringCloud 精彩博文 | |
---|---|
nacos 实战(史上最全) | sentinel (史上最全+入门教程) |
SpringCloud gateway (史上最全) | 更多专题, 请参见【 疯狂创客圈 高并发 总目录 】 |
背景:
下一个视频版本,从架构师视角,尼恩为大家打造高可用、高并发中间件的原理与实操。
目标:通过视频和博客的方式,为各位潜力架构师,彻底介绍清楚架构师必须掌握的高可用、高并发环境,包括但不限于:
-
高可用、高并发nginx架构的原理与实操
-
高可用、高并发mysql架构的原理与实操
-
高可用、高并发nacos架构的原理与实操
-
高可用、高并发rocketmq架构的原理与实操
-
高可用、高并发es架构的原理与实操
-
高可用、高并发minio架构的原理与实操
why 高可用、高并发中间件的原理与实操:
实际的开发过程中,很多小伙伴聚焦crud开发,环境出了问题,都不能启动。
作为架构师,或者未来想走向高端开发,或者做架构,必须掌握高可用、高并发中间件的原理,掌握其实操。
本系列博客的具体内容,请参见 Java 高并发 发烧友社群:疯狂创客圈
分布式文件系统应用场景
互联网下海量的非结构化存储的需求背景下,比如:
- 电商网站,存储海量的商品图片
- 视频网站,海量的视频文件
- 网盘,海量的文件
- 社交网站等等
在这样的背景下,传统的FastDFS部署太过于繁琐,动不动就是来个nginx,然后配置一堆参数和设置,尤其是做分布式的时候,那维护成本一下就上来了,从维护和部署的角度,FastDFS不是一个好的选择,而从迭代的角度,FastDFS早就不维护了,有很多需求是无法
支持到的,那么就需要你自己思考写源码打包了。
同理HDFS部署也不简单,而且Hadoop适合超大文件的存储,并且文件都需要分片,应用场景更多是计算处理,实时数据分析,并且其实HDFS比较吃硬件设备,因为偏于计算,所以对CPU的要求比较高,对于中小企业的业务量并没有这么大,所以应用场景这块也比较
难接触到,但是HDFS的功能还是十分强大的!!还是根据业务进行选型。
存储方案的选型
以下选型方案,来自于探探
这是探探app的几个功能,它的基础功能非常简单左划右划,左划是不喜欢,右划是喜欢,当两个人相互喜欢就配对成功了,配对成功之后就开始相互聊天。
你所看到的一些图片、视频还有在聊天中产生的语音,这些元素在对象存储的范畴里面,就是以对象保存下来。
随着用户量的增长,探探所要存储的对象越来越多。
探探存储的文件类型
这是探探2019年的文件存储数据.
- 数据的体量为:
在不同类型对象所占的空间中,显而易见图片是存储的一个大头,超过了 1PB,它定期清理所以大小基本上保持了稳定的状态。
- 访问的吞吐量数据为:
写入的 QPS 大概是 1 千左右,读取是 5 千左右,压力不是很大。
方案选型
于是,探探团队就开始调研当前的一些开源方案,这些存储方案里面可以分为两种:
-
一种是可以自定对象名称的;
-
另外一种是系统自动生成对象名称。
探探的对象名是自己生成的,里面包含了业务逻辑。
像 FS 就是国内大佬开源的一个分支存储,但是因为不能自定义文件名所以不合适,左划掉。
还有像领英的 Ambry、MogileFS 其实都不能自定对象名的,所以是不合适的。
左上角 LeoFS 对探探来说不是很可控,所以不合适。
TFS 是淘宝开源的,但是目前已经很少有人维护它并且也不是很活跃,所以当时就没有考虑。
ceph 是一个比较强大的分布式存储,但是它整个系统非常复杂需要大量的人力进行维护,和探探的产品不是很符合,所以暂时不考虑。
GlusterFS 为本身是一个非常成熟的对象存储的方案。2011年左右被收购了,他们原版人马又做了另外一个存储系统MINIO,仙鹤就是他们的 logo。
MINIO 的文档非常详细、具体,再加上他们之前在存储方面有十几年的经验,所以就这样打动了探探团队,作为选型的标的。
MinIO 介绍
Minio 是个基于 Golang 编写的开源对象存储套件,虽然轻量,却拥有着不错的性能。
官网地址:MinIO | High Performance, Kubernetes Native Object Storage
何为对象存储?
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。
它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。
对于中小型企业,如果不选择存储上云,那么 Minio 是个不错的选择,麻雀虽小,五脏俱全。
当然 Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、MicroSoft Azure。
MINIO 基础概念
MINIO 有几个概念比较重要:
-
Object:存储到 Minio 的基本对象,如文件、字节流,Anything...
-
Bucket:用来存储 Object 的逻辑空间。每个 Bucket 之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文件夹。
-
Drive:即存储数据的磁盘,在 MinIO 启动时,以参数的方式传入。Minio 中所有的对象数据都会存储在 Drive 里。
-
Set
即一组 Drive 的集合,分布式部署根据集群规模自动划分一个或多个 Set ,每个 Set 中的 Drive 分布在不同位置。一个对象存储在一个 Set 上。(For example: {1...64} is divided into 4 sets each of size 16.)
- 一个对象存储在一个Set上
- 一个集群划分为多个Set
- 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算得出
- 一个SET中的Drive尽可能分布在不同的节点上
Set /Drive 的关系
Set /Drive 这两个概念是 MINIO 里面最重要的两个概念,一个对象最终是存储在 Set 上面的。
我们来看下边 MINIO 集群存储示意图,每一行是一个节点机器,这有 32 个节点,每个节点里有一个小方块我们称之 Drive,Drive 可以简单地理解为一个硬盘。
图中,一个节点有 32 个 Drive,相当于 32 块硬盘。
Set 是另外一个概念,Set 是一组 Drive 的集合,图中,所有蓝色、橙色背景的Drive(硬盘)的就组成了一个 Set.
MIINO如何写入对象?
MINIO 是通过数据编码,将原来的数据编码成 N 份,N 就是一个 Set 上面 Drive 的数量,后面多次提到的 N 都是指这个意思。
上图中,一个 Set 上面 Drive 的数量,是3.
对象被编码成N份之后,把每一份,写到对应的 Drive 上面,这就是把一个对象存储在整个 Set 上。
一个集群包含多个 Set,每个对象最终存储在哪个 Set 上是根据对象的名称进行哈希,然后影射到唯一的 Set 上面,这个方式从理论上保证数据可以均匀的分布到所有的 Set 上。
根据的观测,数据分布的也非常均匀,一个 Set 上包含多少个 Drive 是由系统自动根据集群规模算出来的,当然,也可以自己去配置。
一个 Set 的 Drive 系统会考虑尽可能把它放在多的节点上面,保证它的可靠性。
Minio存储架构
Minio针对不同应用场景也设置了对应的存储架构:
单主机,单硬盘模式
该模式下,Minio只在一台服务器上搭建服务,且数据都存在单块磁盘上,该模式存在单点风险,主要用作开发、测试等使用
启动的命令为:
minio --config-dir ~/tenant1 server --address :9001 /disk1/data/tenant1
单主机,多硬盘模式
该模式下,Minio在一台服务器上搭建服务,但数据分散在多块(大于4块)磁盘上,提供了数据上的安全保障
minio --config-dir ~/tenant1 server --address :9001 /disk1/data/tenant1 /disk2/data/tenant1 /disk3/data/tenant1 /disk4/data/enant1
多主机、多硬盘模式(分布式)
该模式是Minio服务最常用的架构,通过共享一个access_key和secret_key,在多台(2-32)服务器上搭建服务,且数据分散在多块(大于4块,无上限)磁盘上,提供了较为强大的数据冗余机制(Reed-Solomon纠删码)。
export MINIO_ACCESS_KEY=<TENANT1_ACCESS_KEY>
export MINIO_SECRET_KEY=<TENANT1_SECRET_KEY>
minio --config-dir ~/tenant1 server --address :9001 http://192.168.10.11/data/tenant1 http://192.168.10.12/data/tenant1 http://192.168.10.13/data/tenant1 http://192.168.10.14/data/tenant1
分布式Minio有什么好处?
在大数据领域,通常的设计理念都是无中心和分布式。Minio分布式模式可以帮助你搭建一个高可用的对象存储服务,你可以使用这些存储设备,而不用考虑其真实物理位置。
数据保护
分布式Minio采用 纠删码来防范多个节点宕机和位衰减bit rot
。
分布式Minio至少需要4个硬盘,使用分布式Minio自动引入了纠删码功能。
高可用
单机Minio服务存在单点故障,相反,如果是一个有N块硬盘的分布式Minio, 只要有N/2硬盘在线,你的数据就是安全的。
不过你需要至少有N/2+1个硬盘来创建新的对象。
例如,一个16节点的Minio集群,每个节点16块硬盘,就算8台服務器宕机,这个集群仍然是可读的,不过你需要9台服務器才能写数据。
注意,只要遵守分布式Minio的限制,你可以组合不同的节点和每个节点几块硬盘。
比如,你可以使用2个节点,每个节点4块硬盘,也可以使用4个节点,每个节点两块硬盘,诸如此类。
一致性
Minio在分布式和单机模式下,所有读写操作都严格遵守read-after-write一致性模型。
MinIO的数据高可靠
Minio使用了Erasure Code 纠删码和 Bit Rot Protection 数据腐化保护这两个特性,所以MinIO的数据可靠性做的高。
Erasure Code纠删码
纠删码(Erasure Code)简称EC,是一种数据保护方法,它将数据分割成片段,把冗余数据块扩展、编码,并将其存储在不同的位置,比如磁盘、存储节点或者其它地理位置。
从数据函数角度来说,纠删码提供的保护可以用下面这个简单的公式来表示:n = k + m。变量“k”代表原始数据或符号的值。变量“m”代表故障后添加的提供保护的额外或冗余符号的值。变量“n”代表纠删码过程后创建的符号的总值。
举个例子,假设n=16,代表有16块磁盘,另外,有10份原始文件一模一样,称为k,16 = 10 +m,这个m就是可以恢复的校验块个数,所以m是6,任意6个不可用,原始文件都可以恢复,极端情况,10个原始文件坏掉6个,靠4个原始的加上6个校验块,可以把坏掉的6个原始文件恢复,这个用到数学行列式矩阵知识,不做展开。
MinIO的编码方式,将一个对象编码成若干个数据块和校验块,我们简称为Erasure Code码,这个是编码的类型,这种编码的类型,还需要算法来实现,minio 采用的是 Reed-Solomon算法。
MinIO使用Reed-Solomon算法,该算法把对象编码成若干个数据块和校验块。
Reed-Solomon算法的特点:
- 低冗余
- 高可靠
为了表述方便,把数据块和校验块统称为编码块,之后我们可以通过编码块的一部分就能还原出整个对象。
Reed-Solomon code
Reed-Solomon 是纠删码的实现算法的一种,当然,也是一种恢复丢失和损坏数据的数学算法,
Minio默认采用Reed-Solomon code将数据拆分成N/2个数据块和N/2个奇偶校验块。
这就意味着如果是16块盘,一个对象会被分成8个数据块、8个奇偶校验块,你可以丢失任意8块盘(不管其是存放的数据块还是校验块),你仍可以从剩下的盘中的数据进行恢复。
如上图,如我们所知,一个对象存储在一个Set上面,这个Set包含16个Drive,其中灰色的一半是数据库,橙色的一半是校验块,这种方式最多能忍受一半的编码丢失或损坏。
所有编码块的大小是原对象的2倍,跟传统多副本存储方案相比,他只冗余存了一份,但可靠性更高。
纠删码的工作原理和RAID或者副本不同,像RAID6只能在损失两块盘,或者以下的情况下不丢数据,而Minio纠删码可以在丢失一半的盘的情况下,仍可以保证数据安全。
而且Minio纠删码是作用在对象级别,可以一次恢复一个对象,而RAID是作用在卷级别,数据恢复时间很长。
Minio对每个对象单独编码,存储服务一经部署,通常情况下是不需要更换硬盘或者修复。
此外,针对不同应用所需的数据安全级别不同,Minio还提供了存储级别(Storage Class)的配置,调整数据块和校验块的比例,做到对空间的最佳使用。
比如在将比例调整为14:2后,存储100M的数据占用的空间仅为114M。
Bit Rot Protection:
接下来讲Bit Rot Protection,直译就是腐烂。
它只是物理设备上的一些文件细微的损坏,还没有被操作系统所硬件所察觉,但是他已经损坏了。
Bit Rot 位衰减又被称为数据腐化Data Rot、无声数据损坏Silent Data Corruption,
位衰减可以理解为无形中的数据丢失——或者称为“Bit rot”, 是指物理存储介质的衰减所带来的隐患将凸显出来。
位衰减是目前硬盘数据的一种严重数据丢失问题。
硬盘上的数据可能会神不知鬼不觉就损坏了,也没有什么错误日志。
一项对150万块硬盘的研究表明,每90块硬盘就有1块有这种“软错误”,这个错误不但会导致数据丢失,还会导致RAID错误。
针对这一问题,最新的Minio采用了HighwayHash算法计算校验和来防范位衰减,根据测试结果,其可以实现10GB/s的处理速度。
大致的做法是:
MinIO把之前的编码块进行 HighwayHash 编码,最后要校验这个编码,以确保每个编码是正确的。
文件的修复
另外,MinIO提供了一个管理工具,可以对所有编码块进行校验,如果发现编码块有问题,再去修复它。
得益于Reed-Solomon纠删码,Minio可以更加灵活的对文件进行修复。
目前,Minio提供了全量、bucket、文件夹、文件等各个粒度的修复操作:
递归修复
$ mc admin heal -r myminio
指定桶修复
$ mc admin heal -r myminio/dev
下面是几个例子:
相比一般的RAID方式,Minio可以在非常小的粒度下对文件进行修复操作,灵活性有了很大提高。
修复后,可以JSON格式列出指定路径(文件、大小)
$ mc ls -r --json myminio/dev
{
"status": "success",
"type": "file",
"lastModified": "2019-05-30T09:43:07.763-04:00",
"size": 44996289,
"key": "myFile",
"etag": "bae58dc18zzzzz54c14e233b520e0a"
}
部署实操
Minio 提供了两种部署方式:
- 单机部署
- 分布式
两种部署方式都非常简单,其中分布式部署还提供了纠删码功能来降低数据丢失的风险。
单机部署:
minio server /data
分布式部署:
export MINIO_ACCESS_KEY=<ACCESS_KEY>
export MINIO_SECRET_KEY=<SECRET_KEY>
minio server http://host{1...n}/export{1...m} http://host{1...o}/export{1...m}
Docker Compose部署
官方的文档:
https://docs.min.io/cn/deploy-minio-on-docker-compose.html
Docker Compose允许定义和运行单主机,多容器Docker应用程序。
使用Compose,您可以使用Compose文件来配置MinIO服务。 然后,使用单个命令,您可以通过你的配置创建并启动所有分布式MinIO实例。 分布式MinIO实例将部署在同一主机上的多个容器中。 这是建立基于分布式MinIO的开发,测试和分期环境的好方法。
环境说明
操作系统 | ip地址 | docker版本 | Docker Compose版本 |
---|---|---|---|
centos 7.6 | 192.168.31.34 | 19.03.8 | 1.24.1 |
运行分布式MinIO
在Docker Compose上部署分布式MinIO,请下载docker-compose.yaml到你的当前工作目录。Docker Compose会pull MinIO Docker Image,所以你不需要手动去下载MinIO binary。然后运行下面的命令
docker-compose pull
docker-compose up -d
现在每个实例都可以访问,端口从9001到9004,请在浏览器中访问http://127.0.0.1:9001/
注意事项
-
默认情况下Docker Compose file使用的是最新版的MinIO server的Docker镜像,你可以修改image tag来拉取指定版本的MinIO Docker image.
-
默认情况下会创建4个minio实例,你可以添加更多的MinIO服务(最多总共16个)到你的MinIO Comose deployment。添加一个服务
- 复制服务定义并适当地更改新服务的名称。
- 更新每个服务中的命令部分。
- 更新要为新服务公开的端口号。 另外,请确保分配给新服务的端口尚未使用。
关于分布式MinIO的更多资料,请访问这里.
-
Docker compose file中的MinIO服务使用的端口是9001到9004,这允许多个服务在主机上运行。
访问MinIO
http://192.168.31.34:9001/minio/
用户名:minio,密码:minio123
登录之后,效果如下:
MinIO操作
修改密码
点击右上角
提示:无法通过浏览器更新此用户的凭据
注意:如果需要修改密码,修改docker-compose.yaml中的MINIO_ACCESS_KEY和MINIO_SECRET_KEY变量即可。
创建bucket(文件夹)
先来创建一个bucket
创建data
上传文件
选中data,点击右下角的上传文件
选择一张图片,上传成功之后,效果如下:
查看bucket文件信息
点击data,查看与设置该Object的基本信息:
查看共享地址Shareable Link
设置到期时间,最大可保存时间为7天
对话框上方弹出该Object现剩余到期时间
附录1:Minio纠删码的补充学习
Minio使用纠删码erasure code
和校验和checksum
来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。
什么是纠删码erasure code
?
纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code 算法将对象拆分成N/2数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复,是不是很NB,感兴趣的同学请FQgoogle。
为什么纠删码有用?
纠删码的工作原理和RAID或者复制不同,像RAID6可以在损失两块盘的情况下不丢数据,而Minio纠删码可以在丢失一半的盘的情况下,仍可以保证数据安全。 而且Minio纠删码是作用在对象级别,可以一次恢复一个对象,而RAID是作用在卷级别,数据恢复时间很长。 Minio对每个对象单独编码,存储服务一经部署,通常情况下是不需要更换硬盘或者修复。Minio纠删码的设计目标是为了性能和尽可能的使用硬件加速。
Minio纠删码实验
1. 前提条件:
安装Minio- Minio快速入门
2. 以纠删码模式运行Minio
示例: 使用Minio,在12个盘中启动Minio服务。
minio server /data1 /data2 /data3 /data4 /data5 /data6 /data7 /data8 /data9 /data10 /data11 /data12
示例: 使用Minio Docker镜像,在8块盘中启动Minio服务。
docker run -p 9000:9000 --name minio
-v /mnt/data1:/data1
-v /mnt/data2:/data2
-v /mnt/data3:/data3
-v /mnt/data4:/data4
-v /mnt/data5:/data5
-v /mnt/data6:/data6
-v /mnt/data7:/data7
-v /mnt/data8:/data8
minio/minio server /data1 /data2 /data3 /data4 /data5 /data6 /data7 /data8
3. 验证是否设置成功
你可以随意拔掉硬盘,看Minio是否可以正常读写。
附录2:什么是位衰减bit rot
保护?
位衰减又被称为数据腐化Data Rot
、无声数据损坏Silent Data Corruption
,是目前硬盘数据的一种严重数据丢失问题。
硬盘上的数据可能会神不知鬼不觉就损坏了,也没有什么错误日志。
正所谓明枪易躲,暗箭难防,这种背地里犯的错比硬盘直接咔咔宕了还危险。
不过不用怕,Minio纠删码采用了高速 HighwayHash 基于哈希的校验和来防范位衰减。
附录3:Springboot集成MinIO基础实现
新建一个项目springboot-minio,主要代码:
@RestController
@Slf4j
public class FileController {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
@GetMapping("/list")
public List<Object> list() throws Exception {
//获取bucket列表
Iterable<Result<Item>> myObjects = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).build());
Iterator<Result<Item>> iterator = myObjects.iterator();
List<Object> items = new ArrayList<>();
String format = "{'fileName':'%s','fileSize':'%s'}";
while (iterator.hasNext()) {
Item item = iterator.next().get();
items.add(JSON.parse(String.format(format, item.objectName(),
formatFileSize(item.size()))));
}
return items;
}
@PostMapping("/upload")
public ResultBean upload(@RequestParam(name = "file", required = false)
MultipartFile[] file) {
ResultBean resultBean = ResultBean.newInstance();
if (file == null || file.length == 0) {
return resultBean.error("上传文件不能为空");
}
List<String> orgfileNameList = new ArrayList<>(file.length);
for (MultipartFile multipartFile : file) {
String orgfileName = multipartFile.getOriginalFilename();
orgfileNameList.add(orgfileName);
try {
//文件上传
InputStream in = multipartFile.getInputStream();
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(orgfileName).stream(
in, multipartFile.getSize(), -1)
.contentType(multipartFile.getContentType())
.build());
in.close();
} catch (Exception e) {
log.error(e.getMessage());
return resultBean.error("上传失败");
}
}
Map<String, Object> data = new HashMap<String, Object>();
data.put("bucketName", bucketName);
data.put("fileName", orgfileNameList);
return resultBean.ok("上传成功", data);
}
@RequestMapping("/download/{fileName}")
public void download(HttpServletResponse response, @PathVariable("fileName")
String fileName) {
InputStream in = null;
try {
// 获取对象信息
StatObjectResponse stat = minioClient.statObject(
StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
response.setContentType(stat.contentType());
response.setHeader("Content-Disposition", "attachment;filename=" +
URLEncoder.encode(fileName, "UTF-8"));
//文件下载
in = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
IOUtils.copy(in, response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
@DeleteMapping("/delete/{fileName}")
public ResultBean delete(@PathVariable("fileName") String fileName) {
ResultBean resultBean = ResultBean.newInstance();
try {
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
} catch (Exception e) {
log.error(e.getMessage());
return resultBean.error("删除失败");
}
return resultBean.ok("删除成功", null);
}
private static String formatFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + " B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + " KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + " MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + " GB";
}
return fileSizeString;
}
}
yml配置
minio:
endpoint: http://10.12.105.15:9000
accesskey: minioadmin
secretKey: minioadmin
bucketName: chenxin-bucket
启动Springboot项目后,调用localhost:8080/list
用postman上传试下,很明显上传成功了。
同理下载也是一样,看下接口就清楚了,接口后面跟着文件名就可以下载了,当然这个
后面要做成存储到数据库里,这个后面我拓展出来,先会使用再说。
参考代码:https://gitee.com/cx_gitee/springboot-minio
参考文档
https://www.jianshu.com/p/95538d262b93
http://tech.dianwoda.com/2018/12/04/fen-bu-shi-cun-chu-xi-tong-miniojian-jie/
https://www.jianshu.com/p/68ac0477291d
https://studygolang.com/articles/34762
http://docs.minio.org.cn/docs/master/distributed-minio-quickstart-guide
https://blog.csdn.net/qq_31821733/article/details/119882573