MinIO的分布式存储实践方案

基础原理

纠删码

纠删码是分布式存储领域常见的一种冗余技术,与副本机制相对比,纠删码拥有更高的磁盘利用率。纠删码的基本原理:通过纠删码算法对原始数据进行计算,得到冗余的编码数据,并将数据和冗余编码一起存储,如果未来存储介质发生故障,导致其中部分数据出错,此时可以通过对应的重构算法,解码出完整的原始数据,以达到容错的目的。即总数据块 = 原始块 + 校验快(\(n = k + m\))。纠删码技术的磁盘利用率为\(k / (k + m)\),允许总数据块中任意m个数据块损坏。

上面提到的n、m的比值,是衡量纠删码的核心参数,这个值被称为冗余度,冗余度越高(校验快越多),允许丢失的数据块可以越多,同时数据存储成本也就越高。k值决定数据分块的粒度,k越小,数据分散度越小、重建代价越大。k值越大,数据拷贝的负载越大。常见的公有云独享存储的冗余度一般在1.2-1.4左右。

目前常用的纠删码算法:Reed-Solomon,它有两个参数n和m,记为\(RS(n , m)\)。n代表原始数据块个数。m代表校验块个数。

下图中是使用16块磁盘作为存储设备的情况,假设此时MinIOn持有16个磁盘,MinIO会将其中8块作为数据盘,另外八块作为校验盘,数据盘存储对象的原始数据,校验盘存储对象的校验数据。纠删码默认配置是1:1,也就是将所有磁盘中的一半作为数据盘,一半做为校验盘。同时MinIO使用HighwayHash编码计算数据块的hash值,获取文件时会计算hash值来校验文件的准确性。

纠删码的磁盘布局

  • 纠删码缺点
    • 需要读取其他的数据块和校验块
    • 编码解码需要消耗CPU资源
  • 纠删码优点
    • 副本机制对于大文件机极其消耗磁盘空间,纠删码可以通过较少的磁盘冗余,较为高效的解决数据丢失的问题。
  • 应用场景
    • 对于不被长期访问的冷数据,采用纠删码技术,可以大大减少副本数量。

Erasure Sets

MinIO集群会将所持有的磁盘设备(数据盘+校验盘)划分为多个Erasure Sets(EC Set)。EC Set的磁盘数量取值为4-16之间。Ec Set具体划分情况参考2.1节表格。文件通过S3 API传入集群后,通过分片算法找到具体的存储Set,假设当前Set拥有16个磁盘,按照默认的纠删策略,会将整个文件划分成8个数据分片(data shards),再通过纠删码算法算出8个校验分片(parity shards)。

MinIO EC Set模型

MinIO使用EC:N来表示EC Set中存储校验块的磁盘数量,N越大,容错能力越强,占用磁盘空间越多。假设使用EC:2策略,当前总共有4个磁盘,对象会被分为2个数据块,2个奇偶校验块,共4个块,其中允许任意2个出错,但是能正常数据。但是如果需要保证正常读写,需要保证3个磁盘正常(N+1)。上面的参数N可通过MINIO_STORAGE_CLASS_STANDARD参数来指定,最大值为磁盘总数量的一半,最小值为2(开启纠删码功能最小磁盘数量为4)。

EC Set的磁盘数量和对应的默认纠删策略对应如下:

image-20220819174124842

读写流程

  • Write:根据对象名计算出hash得到所处的EC Set,然后创建临时目录,将对象数据写入,直到所有数据写入完成,接下来每次读取10MB,进行EC编码,并将编码数据保存,然后写入meta信息,最终将数据移动到指定存储位置,并删除临时目录。

  • Read:根据对象名获取对应的EC Set,然后去读取meta信息,通过meta信息去做解码,每次读取10MB,在纠删码特性中,如果是默认1:1策略,只需要读取N/2的数据即可完成解码。

  • Server Pool:通过minio server指定的服务端节点集合,可以提供对象存储和检索请求等功能。当有新的Server Pool加入Cluster,bucket的元数据会进行同步,但是其他Server Pool已存储的对象不会同步到新的Server Pool。

    • 例如minio server https://minio{1...4}.example.net/mnt/disk{1...4} 代表一个Server Pool,其中有四个server节点各有4块磁盘。
  • Cluster:集群中包括一个或多个Server Pool。每个hostname参数代表一个Server Pool。MinIO均匀地将对象放入更为空闲的Server Pool。

    • minio server https://minio{1...4}.example.net/mnt/disk{1...4}https://minio{5...8}.example.net/mnt/disk{1...4} 代表有两个Server Pool。

部署方案

部署方案图

单机部署

单机单磁盘:

./minio server --address :50851 --console-address :19003 /data01/miniotest

单机多磁盘(最低四个盘开启纠删功能)

./minio server --address :50851 --console-address :19003 /data01/miniotest /data02/miniotest /data03/miniotest /data04/miniotest

./minio server --address :50851 --console-address :19003 /data0{1...4}/miniotest
挂载磁盘数量(n) EC Set情况
4 <= n <=16 1个
18 2个,每个9个磁盘
19 报错
20 2个,每个10个磁盘
31 报错
32 2个,每个16个磁盘
33 3个,每个11个磁盘
34 报错
35 5个,每个7个磁盘
36 3个,每个12个磁盘

经过验证,挂载数量4 <= n <=16时,EC Set只有一个,并且set中磁盘数即为n。16 <= n <= 32时,n只能取被2整除。

如果n > 32时,n必须有以下集合的公因数(用a表示),共有n / a 个EC Set,每个set有a个磁盘。

集合为:[4 5 6 7 8 9 10 11 12 13 14 15 16]

集群部署

由于集群需要保证数据一致性,因此MinIO使用分布式锁Dsync来实现,Dsync在节点数量少的时候性能很高,随着节点数量增加,性能会出现下降趋势,能保证的最大节点数量为32。如果当前集群节点数量已到达32个,但是仍需要扩容,可以考虑多集群方案:通过负载均衡组件,可以根据header、文件名hash等将请求转发给不同的集群。

分布式部署需要有相同的账号密码,集群节点的时间差不能超过3秒,需要使用NTP来保证时间的一致。集群节点数量必须是大于等于4的偶数。官方建议使用Nginx、HAProxy等组件来实现负载均衡。受限于纠删码策略,MinIO扩容的机器数量必须保持和原有集群数量大小相同或为倍数。不支持扩容单个节点等操作。

将n01-n03三台主机下面的data01-data04的miniotest1作为存储位置。共12块磁盘

./minio server --address :50851 --console-address :19003 http://n0{1...3}.bda.test.com/data0{1...4}/miniotest1

扩容时,末尾添加扩容的节点,并重启集群:

./minio server --address :50851 --console-address :19003 http://n0{1...3}.bda.test.com/data0{1...4}/miniotest1 http://n0{1...3}.bda.test.com/data0{5...8}/miniotest1

监控方案

设置环境变量MINIO_PROMETHEUS_AUTH_TYPE="public",并在Prometheus.yml添加如下配置:

scrape_configs:
- job_name: minio-job
  metrics_path: /minio/v2/metrics/cluster
  scheme: https
  static_configs:
  - targets: ['minio.example.net:9000']W

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!