概述
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。读/写速度上可高达183 GB / 秒 和 171 GB / 秒。
![](https://i-blog.csdnimg.cn/blog_migrate/d1cb4f9185226ff7a00cc9332aed9007.png)
数据组织结构
对象:存储到 Minio 的基本对象,如文件、图片
桶(bucket):是若干个对象的逻辑抽象,是盛装对象的容器。每个 Bucket 之间的数据是相互隔离的。
租户:用于隔离存储资源。在租户之下可以建立桶、存储对象。
用户:在租户下面创建的用于访问不同桶的账号。可以使用MinIO提供的mc命令设置不用用户访问各个桶的权限。
![](https://i-blog.csdnimg.cn/blog_migrate/45736eccaaaa65da79434db83d61635f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0d9689242e4d4142309c773426b31996.png)
Minio架构
MinIO集群采用去中心化无共享架构,各节点间为对等关系,连接至任一节点均可实现对集群的访问,并通过DNS轮询等方式实现节点间的负载均衡。MinIO集群中的所有节点,集元数据存储、数据存储、应用访问等功能于一体,真正实现了去中心化和所有节点的完全对等。其优势在于有效地减少了集群内的复杂调度过程以及因中心节点带来的故障风险和性能瓶颈。
![](https://i-blog.csdnimg.cn/blog_migrate/8b9dacd4e7ab94bb13b58dc13892ef7f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/196ab79ed08b88eb7e3d32664e1893fa.png)
Erasure-Code(纠删码)
它可以将n份原始数据,增加m份数据(用来存储erasure编码),并能通过n+m份中的任意n份数据,还原为原始数据。定义中包含了encode和decode两个过程,将原始的n份数据变为n+m份是encode,之后这n+m份数据可存放在不同的device上,如果有任意小于m份的数据失效,仍然能通过剩下的数据还原出来。也就是说,通常n+m的erasure编码,能容m块数据故障的场景,这时候的存储成本是1+m/n,通常m<n。因此,通过erasure编码,我们能够把副本数降到1.x。
![](https://i-blog.csdnimg.cn/blog_migrate/799e4b0d5efb752edb63d109f9c51e16.png)
MinIO使用Reed-Solomon代码将对象划分为n / 2个数据和n / 2个奇偶校验块-尽管可以将它们配置为任何所需的冗余级别。 这意味着在12个驱动器设置中,将一个对象分片为6个数据和6个奇偶校验块。即使丢失了多达5个((n / 2)–1)个驱动器(无论是奇偶校验还是数据),仍然可以从其余驱动器可靠地重建数据。MinIO的实现可确保即使丢失或无法使用多个设备,也可以读取对象或写入新对象。最后,MinIO的擦除代码位于对象级别,并且可以一次修复一个对象。
![](https://i-blog.csdnimg.cn/blog_migrate/93e086544ccb95b095ce57b4f26dd1f9.png)
关键概念
Drive:部署 Minio 时设置的磁盘,Minio 中所有的对象数据都会存储在 Drive 里。
Set:一组 Drive 的集合,Minio 会自动根据 Drive 数量,将若干 Drive 划分为多个 Set,一个Set的Drive 可以在不同的节点上。
一个对象存储在一个Set上 ,一个集群划分为多个Set。
一个 Set 包含的 Drive 数量是固定的,默认由系统根据集群规模自动计算得出。
Set 下的所有 Drives 划分为 dataDrives 和 parityDrives。
DataDrives :纠删码中的数据盘,用来存储 Object 原始数据。
ParityDrives:纠删码中的冗余盘,用来存储 Object 计算出来的冗余数据。
Minio 纠删码的默认配置为 1 : 1,即数据盘和冗余盘个数相同,所以真正可用的存储空间,只有总空间的一半大小。
![](https://i-blog.csdnimg.cn/blog_migrate/b18d45889099b26e0c5ca1527423cda9.png)
上传流程
1)先根据对象名去做一个Hash,计算出对应的Set,然后来创建临时目录。创建临时目录的目的是为了确保数据强一致性,所以中间数据都会被写入到这个临时目录里
2)接下来读数据编码,每次最多读10M的数据处理,然后做编码,再被写入到磁盘上,循环的过程就是把数据保存下来。
3)数据保存完后,再写meta信息。
4)然后挪到最终的位置上,删除临时目录。
对于上传的 Object,Minio 会将其划分为多个 Block 来计算纠删码。因为一个 Set 中有多个 Drive(数据盘+ 检验盘),所以 Minio 会先将一块 Block 按照 Drives 数量,划分为多个小块,这些小块在 Minio 中叫做 Shards。比如一个 Block 是 10MB, 而 Set 里有 16 个 Drive(8 个数据盘 + 8 检验盘),此时 Minio 会将 Block 按照 10 MB / 8 DataDrives 的方式,将数据划分到 8 个 数据块,并额外再创建 8 个 空 Shards,用来存储编码后的冗余数据。
接着 Minio 就会对 Data Shards 进行纠删码编码,并将编码后的冗余数据存储到前面创建的 8 个空 Shards 中,也就是 parity shards 中。
![](https://i-blog.csdnimg.cn/blog_migrate/e8a5d40195ee6e471e55932cb4ed2ba8.png)
下载流程
1)先根据对象名做Hash,找到对象对应的Set
2)然后去读取meta信息,通过meta信息来获得编码的方式,然后去解码。它是以10M数据做EC编码,读的时候也是逐个part解析,每个part给他做解码,然后写入到一个io write里面。
备注:做EC码时,只要一半的编码块就能还原整个对象,所以读meta时读了N份,但是读数据时只要读N/2就可以了
![](https://i-blog.csdnimg.cn/blog_migrate/1826a470db68bc6e3f73a5858a9842aa.png)
分布式锁管理(DLM)
与分布式数据库相类似,MinIO对象存储系统也面临数据一致性问题:一个客户端程序在读取一个对象的同时,另一个客户端程序可能正在修改或者删除这个对象。
dsync是一个用于在n节点网络上进行分布式锁的包。它的设计考虑到了简单性,因此提供了有限的可扩展性 ( n <= 32)。每个节点将连接到所有其他节点,并且来自任何节点的锁定请求将被广播到所有连接的节点。如果n/2 + 1节点(无论是否包括其自身)积极响应,则节点将成功获得锁定。如果获得了锁,它可以被持有,只要客户愿意,之后需要释放。这将导致释放被广播到所有节点,之后锁再次可用
![](https://i-blog.csdnimg.cn/blog_migrate/33218293bd67a22899799547f2c4f8ba.png)
关于扩容
局限1、搭建集群后,不允许扩容
MinIO一旦集群搭建成功后,就不可以更改集群节点数。因为存在在MinIO的对象到底存储在哪个Set,是通过名字做Hash去找的,一旦节点数变了落点就错乱了。
局限2、大集群最大节点数为32
MinIO实现了一个峰值锁叫DSync。它在节点数量少时,性能非常高;但节点数量过多时,性能就下降了。功能实现的最大节点就是32,所以导致MinIO单个集群的最大节点数也是32。
官方回复是,他们十年做GlusterFS的经验看,一个超大的集群是难以维护的,尤其是宕机之后的恢复时间也特别长,所以他们在做MinIO的时候一个核心设计理念就是简单,易于维护。
扩容方案
1、可同时向多个集群写入
2、当集群容量达到阈值,从写集群中剔除,变成只读
3、读取的时候,根据编码到文件名上的集群信息,从而路由到正确的集群。
MinIO本身提供一个叫联合模式的方式来组建集群,但是要额外引入其他依赖。可以考虑在LB层根据其请求里面的一些header信息做流量转发。
当配置多个集群的时候,可以先从配置中获取可用的集群,再从LB上根据请求的header信息,可控制向哪个集群写。当某个集群的容量达到阈值时,可以从配置中剔除该集群,把他变成只读集群。读取的时候把集群ID或信息码编码到文件名上去,这样可以通过解析文件名就能获取到对应的集群。