同事新部署了一个minio集群,用了3台服务器,每个服务器上配置了3个目录;还有一个集群,也是3台服务器,每个服务器上配置了2个目录。

那么,能不能用3台服务器,每个服务器上1个目录呢?

不能。minio的备份机制与HDFS、盘古之类不同。

HDFS、盘古,是一份数据3份副本,只要还有一个机器在,数据就不会丢失。但这样磁盘的利用率其实挺低的,只有原始容量的1/3。

而minio使用erasure code(纠删码)的机制来解决数据的可靠性。这个机制对目录数有要求。

纠删码通过算法将原始的数据(data)进行编码得到冗余(parity),并将数据和冗余一并存储起来(data+parity),以达到容错的目的。其思想是将n块原始的数据元素通过一定的计算,得到m块冗余元素(校验块)。

对于这n+m块的元素,当其中任意的x块元素出错(包括原始数据和冗余数据)时,均可以通过对应的重构算法恢复出原来的n块数据。生成校验的过程被成为编码(encoding),恢复丢失数据块的过程被称为解码(decoding)。磁盘利用率为n/(n+m)。

基于纠删码的方法与多副本方法相比具有冗余度低、磁盘利用率高等优点,但计算、网络开销大,恢复效率低。

存储系统通常使用RS(Reed Solomon)码。有关纠删码的知识,请参阅纠删码(Erasure Code)浅析,写的非常详细。

简单来说,RS码有两个参数n和m,记为RS(n,m)。n代表原始数据块个数。m代表校验块个数。其关键点为2个矩阵的生成:

  • 编码时生成范德蒙矩阵(B矩阵,上半幅图)
  • 解码时根据剔除损坏数据对应的B矩阵生成逆矩阵。有了逆矩阵,就可以利用剩余的数据来恢复原始数据。(下半幅图)

f1

具体到minio:通常n=m=disks/2,disks即为前述的目录。例如在1个有16 disks的集群上,一个对象会被拆为8份数据文件,这些文件中保存的是原始的数据(可以用文本文件做个试验,此时可以看到文本文件被均匀的分为了n份,每份存储的均为明文);除了8份原始数据文件,还会生成8份纠错码文件。

erasure-code

这样,即使有一半的disk坏了,仍然可以恢复出来原始的数据。

但是,如果要想创建新对象,则至少需要 (disks/2 + 1)个disks在线。

erasure code的机制相对于多副本,其数据更新、恢复的代价都比较高,那minio为什么要选择erasure code呢?原因是,通常minio用来存储的都是一些冷数据,更新不频繁,这种场景下用RS码就显得非常经济实惠了。例如,可以将minio集群作为registry的后端,用来存储容器的数据。

回到刚刚的问题,为什么minio必须至少要4个节点呢?原因就是因为采用了纠错码的机制,如果3个disks的话,RS码就失效了。

另外minio还有一个最大16 driver的限制,不过我觉得这似乎是minio自己加的,RS码本身要求shard不要超256即可。

minio使用了klauspost的reedsolomon,这是一个golang实现的RS码。

Ref: