Skip to content

Latest commit

 

History

History
125 lines (60 loc) · 12.8 KB

minio_thinkin.md

File metadata and controls

125 lines (60 loc) · 12.8 KB

Min.IO ThinkIn

Min.IO 特点

极简化设计

首先,集群架构是去中心化的架构没有单独维护元数据(部分元数据作为对象存储在集群中),所有的存储节点对等(所有节点掌握全局拓扑信息),避免了很多复杂的协调逻辑(处理数据修复)。其次,核心的存储层(ObjectLayer 层及其子类)设计简单,erasureZones、erasureSets、erasureObjects 功能单一且清晰,xlStorage 利用 直接 IO 和 BitRot 提升性能和可靠性。最后,集群模式的启动参数简单易用,扩容方式亦是(通过参数计算拓扑接口和一些约束,在启动阶段计算,需要深入解析才能掌握)。

兼容 AWS S3 语义

Min.IO 设计之初就明确兼容 AWS S3 的接口,而且也是目前开源社区兼容度非常高的一个项目。从代码组织架构上看 min.io/pkg 很多单独开发的库都是为了兼容 S3 做的准备,可见其设计初衷。从安全、权限管理、通知机制、S3 语义的对象锁、资源管理等多个维度都有非常高度的兼容,并且 S3 API 兼容的数量也是难得的有非常高的兼容度。相比社区其他产品,大多数是先有了自身的架构或者其他的核心设计理念,后期对 S3 进行兼容,这种项目往往兼容度不高,究其原因在设计之初的架构、引擎等层面做不到。

公司级产品

从设计之初的理念和代码组织架构上以及代码质量上看,Min.IO 都是一个公司级的产品,而非个人的开源项目(槽点是国内社区不是很活跃,相关技术文章过少,大多只是部署相关的内容,并未涉及到内核)。从始至终贯穿了极简的设计理念、核心代码的层次设计清晰且解耦性良好,可见研发团队功底。

Min.IO 不足

头重脚轻

Min.IO 代码量还是很大的,单 min.io/cmd Min.IO层的逻辑(没有考虑自研的一些 pkg 库)就有 10w+ 行代码,但是核心的存储层代码量是 1.2w+,其余大部分逻辑是用于兼容 S3。如果项目本身对兼容 S3 没有过多要求(公司内部私有云场景等),就显得有一些头重脚轻,将近 8w 行兼容 S3 的代码也会加大线上问题定位和学习成本,S3 的客户端相对一般对象接口也略微复杂(签名、加密、并且使用了很多 Http Head 字段等等),加大了业务学习成本,如非必要,大可不必。

正是过多兼容 S3 的逻辑,使得极简设计理念的 Min.IO 现有有一些头重较轻(针对对 S3 接口没有过重要求的场景,如果强烈要求兼容 S3,这就不是问题啦)。AWS S3 没有开源,但是通过一些技术文章、官网暴露的一些信息、以及内部人士的交流,S3 产品背后应该是若干个项目的整体表现,既各个子系统是解耦的,比如:权限系统是 AWS 个产品线通用的、配置管理等等,而非像 Min.IO 都集中在一个项目或者一个进程中,从这个角度看,Min.IO 过分了拟合了 S3 的功能于一身(为了简化使用,将所有功能写进一个进程,写入一个进程有导致系统间解耦不好,正是架构设计的学问啊!哈哈哈)。

Min.IO 对资源约束
场景

根据 Min.IO 启动参数 的介绍,可扩展的分布式集群的所有启动参数必须带有 “{……}” 模式,每一个参数代表一个 zone,扩容即是 zone 级别的扩容,在源集群参数的基础上添加新的 zone 资源参数启动新的集群所有节点完成扩容。

如果所有启动参数中有一个参数没有 “{……}” 模式(有的有,有的没的会启动失败,要么都有,要么都没有,参数解析时的应限制),则所有参数被认为是在一个 zone,无法做到 zone 级别的扩容,如果在扩容时强行在原有集群参数后面加新的扩容资源参数,会被认为是重新启动集群。此时会根据新的参数,重新计算 RS 编码组内的分块数量和 RS 的分组数量(详见 Min.IO 启动参数),此时原有集群的数据需要进行 rehash,因为 zone 内 Set 的选择是 hash 方式,zone 内 Set 数量变化了,需要重新 hash。否则,源集群有脏数据,查询旧数据可能失败。

Min.IO 认为 rehash 给系统带来了复杂性且消耗系统内部资源, 不符合极简的设计理念Min.IO 的方案是 zone 级别的扩容,可以避免给系统带来上述的复杂性和系统资源消耗。

举例

  • 带有 “{……}” 模式 的启动参数扩容

    • 源集群的启动参数: http://host{1...4}/export{1...4}

      16块盘,4个节点,会形成一个 zone,一个 Set,既RS 编码的分组,分组内 16个分块(8个数据块、8个校验块)

    • 扩容时的启动参数: http://host{1...4}/export{1...4} http://host{5...8}/export{1...4})

      遍历参数(上述是2个参数)顺序执行相同的计算逻辑,第一个参数的计算结果与源集群相同,第二个参数也是 16块盘,4个节点,计算的数量亦是相同,相当于扩容了一个 zone

      注意:

      1. 如果多个参数计算完的 RS 分组内的分块数量必须一致,否则启动失败
      2. 如果多个参数计算之后的启动类型(单机、分布式、可扩展分布式,具体判断逻辑见Min.IO 启动参数,若是分布式可扩展集群,每个参数还必须是两台机器,那么 host 必须也得使用 "{……}" 模式才能保证是两台集群在一个 zone 内。
  • 不带有 “{……}” 模式 的启动参数扩容

问题

上面是比较详细的举例说明了参数对集群启动模式的影响,这些其实都会对资源造成一定的约束:

  1. 机器 IP 具备一定的连续性,否则无法组织成 {……} 模式的参数。
  2. 每台机器上的磁盘必须同构,否则无法组织成 {……} 模式的参数。
    1. 即使挂在在一块磁盘(程序有校验,单没做强制要求),仍然有问题,比如多个目录挂在一块磁盘上,方便组织成了 {……} 模式的参数,但是数据的可靠性会有影响,一块磁盘故障可能导致 多数的 RS 分组内的分块无法使用。
    2. 并且多个目录公用一块磁盘,每个 RS 分组的容量计算就会有重复,导致容量计算不准(xlstorgae 调用系统调用查看磁盘容量),可能命名查看容量时有容量,容量耗尽提前了。

上述约束可能远比看得更麻烦,系统一定要注重其运行场景,比如:公司内资源申请由自业务方根据需求沈琼,申请存储服务时交付机器,交付的机器讲师参差不齐的,很少情况可以预先搭建一个庞大的且整齐(完全符合服务提供方需求)的集群,供业务使用一年及以上,甚至6个月都难做到,都是随着容量或者轻量的增长逐步增加,视情况协调资源。

针对公司级的服务,比较实际可行的方案是对机型不做过多要求,在架构和引擎设计时要考虑资源的异构性。

解决

要想解决上述约束问题,就要深究造成的原因并熟悉其原理找到合适方案。参数在整个的生命周期中只在启动阶段起作用,并非系统的重点,Min.IO 却做了十足的功课,目的只有一个,极简的设计理念推动下简化业务的使用成本,参数越简单,起步阶段学习成本越低,甚至有拿来即用的快感(但是想要用好,并驾驭一个系统不经过深度的学习和长时间的线上实践,永远是行不通的)。

上述问题并不是不可解决的,业务使用简单的原因是 Min.IO 把参数复杂的解析逻辑自己实现了(做到了用户的”傻瓜式“使用),并最终在每块磁盘上生成 format.json 文件,该文件根据参数解析的记过在存储层初始化阶段生成的拓扑信息,例如 zone、RS 等信息。如果开发人员对 Min.IO 完全熟悉,完全可以根据自身的资源情况生成其 formate.json 文件(通过脚本或者 cli 等运维工具,根据公司实际情况生成),然后通过 pass 平台 或者 脚本发布到资源的磁盘上,阉割 Min.IO 启动阶段的参数解析部分逻辑,启动之后加载 formate.json 初始化存储层 和 一些全局变量。

开发人员负责生成 formate.json 的部署方案的本质是将参数解析的逻辑从 Min.IO 中剥离出来,好处是灵活性把握在自己手里,相当于用实现的复杂性换来了根据资源情况部署的灵活性,进而接触了对资源的约束。

集群扩展(非 CoreDNS 模式)

Min.IO 从设计的角度看可以在 zone 级别的无限扩展。对于绝大多数系统的发展历程,系统都是从小逐渐发展变大,起步可能几台机器,一般发展到几百台机器,BAT 量级的公司单机群会发展到万台级别的规模,亚马逊、谷歌更是早早突破单机群 10w+ (并且是全球部署,国内的技术发展目前主要同城跨机房,个别有国内跨区域,这与全球跨洲际部署对技术的要求还是有区分度的)。

正如上部分介绍,在多数的公司环境下很难初始阶段部署足够大的集群(支撑半年以上业务的需求),都是逐步添加资源扩展集群。对于 Min.IO 集群来说,一个1k 左右的集群,内部可能有几十甚至更多的小分布式集群,要是业务发展(多个业务线,公司级别服务)到 1w 规模的集群可能有成百上千个集群。Min.IO 集群内有过多的小分布式集群会引进一些问题,最直接的影响是读写流程中,会遍历所有的 zone 查看是否有要查询的数据,对于读有则返回,对于写有则继续卸载相同的 zone 内,没有则随机选一个 zone (随机性与容量相关)写入,这个过程会有请求放大。

举例

  • Min.IO 可扩集群内部有 100个 小的分布式集群,既 100个 zone,内部是 RS 编码都是 4个分块。
    • 一个未命中读请求需要 100 * 4 个请求
    • 一个命中的读请求平均 也需要 200 个请求
    • 一个未命中的写请求,需要 100 * 4 + 4个请求
    • 一个命中的写请求平均 也需要 200 + 4 个请求

请求放大程度与 zone 的个数 和 RS 编码分块数相关(在这里重点讨论前者),zone 的个数与其 zone 内的容量 和 性能相关(这里重点考虑容量),zone 是逐步扩展的,在实际情况中如上所述很难一次部署一个较大的 zone,供业务使用半年以上,都是逐步增加,每次增加的量级在几台到几十台左右,增加资源周期以月为单位,这就势必会早上上述请求放大的场景。

小文件过多

导致文件系统对资源开销较大。

测试数据

测试机器:64 core,512 内存,SSD

测试集群:单机模式(主要向看一下引擎层的性能)

测试数据:16个客户端,压测写 80K 数据,qps 在 5200

列一下测试数据的主要目的是与 seaweed 进行一下对比,有一个直观的感受,数据不具备参考意义。Min.IO 性能差不多是单副本 seaweed 的2倍,主要是 Min.IO 去中心架构省去了与 Master 交互的网络请求。值得注意的是,Min.IO 使用的是直接IO,seaweed 使用的是标准 IO。