开源分布式对象存储-MinIO
背景:通常在企业中我们会将一些图片,视频,文档等相关数据存储在对象存储中,以便于数据的存储和快速获取。在过去的一段时间,我们将这部分数据存储在公有云的对象存储服务上,但随着业务的快速发展,我们需要存储一些身份信息用于审核和实名相关的数据,这部分数据较为敏感,因此对于敏感数据的存储我们选择了使用兼容S3协议的开源分布式对象存储-Minio来进行自建服务。
前言
Minio可能在国内知道和用的人不是很多,我第一次接触Minio是也是当时我们需要使用Spinnaker集群来管理和维护内部的Kubernetes集群,而Spinnaker的中的持久化存储就使用的是Minio Spinnaker集群搭建。
但其实,Minio这款开源的分布式对象存储服务在国外已经相当受欢迎,并且国内也有多中小型互联网公司使用它来作为对象存储服务。
有意思的是当年在开源的分布式存储方案中,比较有名的就是GlusterFS
和Ceph
。前者虽然也提供了块存储和对象存储的接口,但对于企业来说更多用于了分布式文件系统存储,其实就是一种高可用版本的NAS解决方案(通常用于替换NFS),而后者则针对多种存储场景设计了不同的产品,针对分布式文件系统存储有CephFS
,针对分布式块存储有Ceph RBD
,针对分布式对象存储有Ceph Radosgw
,基本上可以做到开箱即用。
所以,在后来GlusterFS后来被收购后,据说创始团队又开源了一个分布式存储软件,就是这个用Golang编写的小而美的对象存储Minio.
Minio介绍
MinIO
是一个用Golang
开发的基于Apache License v2.0
开源协议的对象存储服务
。
它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
Minio使用纠删码erasure code
和校验和checksum
来保护数据免受硬件故障和数据损坏。
因此,即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。
纠错码介绍(erasure code)
纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code
将对象拆分成可变数据块
和奇偶校验块
。 比如12块盘(driver),一个对象可以被切分到所有驱动器上的可变数量的数据和奇偶校验块—从6个数据和6个奇偶校验块到10个数据和2个奇偶校验块。
但是,默认情况下,MinIO在N/2
个数据块和N/2
个奇偶校验驱动器上分片对象,当然用户可以通过storage classes来自定义配置,不过官方还是建议采用使用N/2个节点来分配数据块和奇偶校验块,这样能够以最佳的方式保护防止驱动器(driver)故障.
在上面的12个驱动器示例(使用默认配置)中,您可以丢失6个驱动器中的任何一个,但仍然可以从其余驱动器可靠地重构和恢复数据。
为什么纠错码有用
与RAID或复制不同,纠错码可以保护数据不受多个驱动器故障的影响。
比如,在经典的RAID6
中可以在损失两块盘的情况下不丢数据,然而在Minio中纠错码可以保证当一般的盘故障时依然不会影响到数据。此外,纠错码在在对象级别,并且每次就可以修复一个对象。对于RAID
而言,数据的修复在卷(volume)级别,这就意味比较高的修复时间。由于MinIO对每个对象单独编码,所以它可以逐步的对对象进行修复。一旦部署了存储服务器,就不需要在服务器的生命周期内更换或修复驱动器。MinIO的纠错码后端是为提高操作效率而设计的,它可以更加高效的利用硬件而达到加速的效果。
什么是Bit Rot
保护
Bit Rot,也称为Data Rot或静默数据损坏,是当今磁盘驱动器面临的数据丢失问题。驱动器上的数据可能在不发出错误信号的情况下被损坏,这使得比特损坏比永久的硬盘驱动器故障更危险。而在Minio内部的设计中采用了高速的HighwayHash校验和来保护Bit Bot
Drivers是如何使用纠错码的
MinIO将您提供的驱动器分为4、6、8、10、12、14或16个驱动器的纠错码集,因此,在你构建一个Minio集群时,需要确保提供的驱动器的数量是这些数据之一的倍数,然后每个对象都会被写入一个单一的纠错码集中。
Minio会使用尽可能大的EC集(除以给定驱动器的数量),比如,18个驱动器可以配置为3组6个驱动器,但是24个驱动器最大只能分配2组12个驱动器。
驱动器的大小应该大致相同。
Minio集群实操
使用纠错码模式运行minio服务
# 使用二进制方式运行有12个驱动器的minio服务
$ minio server /data1 /data2 /data3 /data4 /data5 /data6 /data7 /data8 /data9 /data10 /data11 /data12
# 使用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
以纠错码方式运行服务后,你就可以尝试将任意一半盘毁坏,依然不会影响整个系统的IO。但是如果要求不影响写,处于正常的的驱动器个数必须大于N/2
分布式MinIO集群
通常情况下,为了成本和效率的考虑开发同学可能会使用上述方式快速创建一个minio服务,但是从稳定性和可用性的角度来考虑,上述方式均无法保证,因此MinIO也提供了分布式的模式。
分布式Minio可以让你将多块硬盘(甚至在不同的机器上)组成一个对象存储服务。由于硬盘分布在不同的节点上,分布式Minio避免了单点故障。
分布式的Minio的优势:
-
数据保护
: 采用纠错码erasure code
防止多节点或者驱动器异常,采用bit rot
来进行数据保护。一个分布式的Minio集群最小需要4块盘(其实是纠错码要求最小4块)来驱动整个集群,当我们启动分布式集群后,纠错码会自动启动 -
高可用
: 多节点组成的分布式minio可保证服务的高可用(一个N节点的分布式Minio,只要有N/2节点在线,你的数据就是安全的。不过你需要至少有N/2 1个节点才能创建新的对象。) -
一致性保障
: MinIO在所有的IO操作中都严格遵循read-after-write
和list-after-write
一致性模型
运行分布式MinIO集群
想要运行一个分布式的MinIO集群,你只需要将驱动器的位置参数传给minio指令即可,然后需要在全部节点运行相同的命令。
注意事项
:
- 所有的节点需要有相同的access key 和 secret key,推荐在启动之前使用
MINIO_ACCESS_KEY
和MINIO_SECRET_KEY
变量来共享key - MinIO创建一组4, 6, 8, 10, 12, 14 or 16个驱动器的纠错码,因此提供的驱动数量必须是前面数字的倍数
- MinIO会选择给定驱动中,较大的一个EC集合,比如8个驱动将会使用一个大小为8的EC集,而不是两个大小为4的EC集
- 每一个对象都会写到一个EC集中,因此对象的分布不可能超过16个驱动
- MinIO集群中的所有节点应该是同构的(比如:相同的OS,相同的磁盘和相同的网络架构)
- MinIO分布式模式需要
fresh directories
(即干净的目录),如果需要可以和其他应用程序共享驱动器(使用子目录的方式) - 运行分布式MinIO实例的服务器之间的间隔应该小于15分钟,你可以使用
NTP
服务来保证服务器时间同步 -
MINIO_DOMAIN
环境变量应该被定义成bucket DNS
样式的支持(可以给每个bucket设置子域名) - 在
Windows
上的分布式集群是实验性的,需要谨慎
注意:
一个EC Set 上包含多少个Drive是由系统自动根据集群规模算出来的,当然你可以自己去配置.
我们以1个驱动器的4节点来组成集群:
# tree -L 1 /opt/app/
/opt/app/
├── minio
├── minio.conf
$ cat minio.conf
MINIO_ACCESS_KEY=BGBiao
MINIO_SECRET_KEY=BGBiao
ENDPOINTS="http://10.0.0.148:9000/data/minio http://172.16.62.149:9000/data/minio http://172.16.62.150:9000/data/minio http://172.16.62.151:9000/data/minio"
$ cat /usr/lib/systemd/system/minio.service
[Unit]
Description=Minio
Documentation=https://docs.minio.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/opt/app/minio
[Service]
EnvironmentFile=-/opt/app/minio.conf
ExecStart=/opt/app/minio server $ENDPOINTS
# Let systemd restart this service always
Restart=always
# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536
# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no
[Install]
WantedBy=multi-user.target
# 将上述配置同步到4个节点,并启动,minio实例之间会自行发现各个节点
$ systemctl restart minio
Minio分布式对象存储服务使用
当使用前面的方式成功运行minio的对象服务后,我们就可以使用以下几种方式进行访问:
-
web
: 默认我们可以访问实例的9000端口,通过access key和secret key进行访问实例 -
mc
: 使用minio官方提供的兼容s3的客户端 -
aws-cli
: 使用aws的客户端命令 -
s3cmd
: 使用3s的开源客户端执行 -
minio-go
: 使用minio的golang客户端操作集群
注意
: 当我们成功运行minio服务后,默认会提供一个简单的web管理页面.
这里我们使用mc
客户端命令进行操作(值得一提的是,有了mc客户端之后操作oss就如同本地操作一样方便快捷
)
minio客户端mc的使用
客户端配置管理
# 添加minio云存储服务(会将数据存入~/.mc/config.json)
# mc config host add <ALIAS> <YOUR-S3-ENDPOINT> <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY> <API-SIGNATURE>
$ mc config host add minio http://bgbiao.top:9000 BGBiao BGBiao S3v4
查看bucket
# 查看minio集群中的bucket
$ mc ls minio
[2020-01-10 20:54:19 CST] 0B test11/
[2019-07-08 19:51:02 CST] 0B test23/
[2019-07-08 20:10:58 CST] 0B test4/
# 查看bucket的内容
$ mc ls minio/test11
[2019-07-05 21:22:34 CST] 88KiB 111
[2019-07-07 11:03:21 CST] 88KiB 112
[2019-07-08 10:50:51 CST] 88KiB 113
[2019-07-08 18:17:17 CST] 88KiB 114
[2019-07-09 11:51:30 CST] 66KiB 116
[2019-07-09 14:24:23 CST] 66KiB 117.jpg
[2019-07-09 14:33:17 CST] 66KiB 118.jpg
[2019-07-09 14:52:36 CST] 66KiB 119.jpg
[2020-01-10 20:52:28 CST] 7.4KiB server.xml
bucket管理
# 创建一个bucket
$ mc mb minio/bgbiao
Bucket created successfully `minio/bgbiao`.
$ mc ls minio/ | grep bgbiao
[2020-01-22 16:32:43 CST] 0B bgbiao/
# rb可以直接删除指定的bucket
$ mc rb minio/bgbiao
Removed `minio/bgbiao` successfully.
# tree可以打印出来bucket组织的文件系统树形结构
$ mc tree --depth 2 --files minio/bgbiao
minio/bgbiao
└─ hostname.txt
# du可以查看某个bucket或者object的大小
$ mc du minio/bgbiao
10B bgbiao
$ mc du minio/
9.1GiB
对象管理
# 将本地文件拷贝到minio的oss服务
# 并直接使用cat命令访问
$ hostname > hostname.txt
$ mc cp hostname.txt minio/bgbiao/
hostname.txt: 10 B / 10 B ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 132 B/s 0s%
$ mc ls minio/bgbiao/
[2020-01-22 16:33:52 CST] 10B hostname.txt
$ mc cat minio/bgbiao/hostname.txt
localhost
# 使用pipe命令可以将标准输入的数据直接写入到minio的存储中
$ echo ${PATH} | mc pipe minio/bgbiao/path.txt
$ mc ls minio/bgbiao/
[2020-01-22 16:33:52 CST] 10B hostname.txt
[2020-01-22 16:43:43 CST] 111B path.txt
$ mc cat minio/bgbiao/path.txt
/Users/BGBiao/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/usr/local/soul/bin
# 受用share命令生成可供外部匿名下载的临时链接地址
# 生成后我们就可以使用共享链接在4小时内随意下载
$ mc share download --expire 4h minio/bgbiao/hostname.txt
URL: http://bgbiao.top:9000/bgbiao/hostname.txt
Expire: 4 hours 0 minutes 0 seconds
Share: http://bgbiao.top:9000/bgbiao/hostname.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BGBiao/20200122/us-east-1/s3/aws4_request&X-Amz-Date=20200122T083619Z&X-Amz-Expires=14400&X-Amz-SignedHeaders=host&X-Amz-Signature=ec49806b7c249bbeb140af759afeff907672ebd97637b759efd11d4f9b1a20b3
# 使用mirror指令对bucket内容进行镜像(最实用的一个指令)
# 将minio这个对象服务下的bgbiao的整个bucket的对象镜像到本地
# 使用minio的mc客户端可以在多个minio服务之间进行数据镜像
$ mc mirror minio/bgbiao .
...iao/hostname.txt: 10 B / 10 B ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 39 B/s 0s %
# 使用find指令来直接查找内容(相对比较实用,find指令支持很多方便快捷的参数,和Linux本地的find命令内容相似)
# 查找名称为*.txt的文件并打印临时url下载地址
$ mc find minio/bgbiao/ --name "*.txt" --print {url}
http://bgbiao.top:9000/bgbiao/hostname.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BGBiao/20200122/us-east-1/s3/aws4_request&X-Amz-Date=20200122T084926Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=a02a370575cae5d5cf92c565d02918e20d734f80afed3e5eebf5fe1433aa348a
http://bgbiao.top:9000/bgbiao/path.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BGBiao/20200122/us-east-1/s3/aws4_request&X-Amz-Date=20200122T084926Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=d7d87f6a4f9d406ae02a6844574f02f6e1479215bee8401feea58e95e98b8b36
# diff命令可以列出两个bucket之间对象的大小,名字,时间的不同
$ mc diff . minio/bgbiao/
> http://bgbiao.top:9000/bgbiao/path.txt
< readme.md
# rm可以直接删除指定的对象(--force --recursive就相当于我们linux中的rm -rf)
$ mc rm --force --recursive minio/bgbiao
Removing `minio/bgbiao/hostname.txt`.
Removing `minio/bgbiao/path.txt`.
minio运维管理
# stat可以查看minio服务的元数据信息
$ mc stat minio/bgbiao
Name : bgbiao/
Date : 1970-01-01 08:00:00 CST
Size : 0 B
Type : folder
$ mc stat minio/bgbiao/hostname.txt
Name : hostname.txt
Date : 2020-01-22 17:04:27 CST
Size : 10 B
ETag : 902f570940ba8d4b74743a3a97f5aff6-1
Type : file
Metadata :
Content-Type : text/plain
X-Minio-Deployment-Id: 80525c40-fec3-459e-8080-6f5210548647
# retention指令可以设置指定前缀的对象的保留时间
# events指令可以查看和添加对象的事件
# watch可以实时监听对象的events
# policy用来管理匿名用户对bucket和object的访问
# 设置bgbiao这个bucket匿名用户仅可以下载(download/public/upload)
$ mc policy set download minio/bgbiao
$ mc policy list minio/bgbiao
# admin用来管理minio服务
# mc admin info 查看minio服务基本信息
# mc admin service 重启和停止minio服务
# mc admin config 管理minio服务的配置信息
$ mc admin info minio
● 10.0.0.149:9000
Uptime: 1 day
Version: 2020-01-16T22:40:29Z
Network: 4/4 OK
Drives: 1/1 OK
● 10.0.0.150:9000
Uptime: 1 day
Version: 2020-01-16T22:40:29Z
Network: 4/4 OK
Drives: 1/1 OK
● 10.0.0.151:9000
Uptime: 1 day
Version: 2020-01-16T22:40:29Z
Network: 4/4 OK
Drives: 1/1 OK
● 10.0.0.148:9000
Uptime: 1 day
Version: 2020-01-16T22:40:29Z
Network: 4/4 OK
Drives: 1/1 OK
13 GiB Used, 2 Buckets, 166,580 Objects
4 drives online, 0 drives offline
# config 用来管理客户端的配置文件(还记得我们刚开始配置本地环境的时候吗)
# minio默认帮我们配置了一些公共的对象存储服务,同时也配置了一个本地的oss服务
$ mc config host list
gcs
URL : https://storage.googleapis.com
AccessKey : YOUR-ACCESS-KEY-HERE
SecretKey : YOUR-SECRET-KEY-HERE
API : S3v2
Lookup : dns
local
URL : http://localhost:9000
AccessKey :
SecretKey :
API :
Lookup : auto
minio
URL : http://bgbiao.top:9000
AccessKey : BGBiao
SecretKey : BGBiao
API : s3v4
Lookup : auto
play
URL : https://play.min.io
AccessKey : Q3AM3UQ867SPQQA43P2F
SecretKey : zuf tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
API : S3v4
Lookup : auto
---欢迎一起交流,一起进步啊。
欢迎关注我的公众号: BGBiao,一起进步~
上一篇: webpack分离css并单独打包的方法
下一篇: php实现读写tab分割的文件