系统构建 大规模块存储 EC
本文整顿自 2023 年 7 月> 十分欢迎大家的来到,当天由我来分享百度默认云块存储 EC 系统的构建。块存储系统在百度默认云的产品名叫 CDS,底层 EC 系统由 Aries 承当。
关于 Aries 的具体引见,可以参考文末「传送门」的第一篇文章。
当天关键引见的内容如下,首先会比拟一下各种容错方式,引见一下咱们决定 EC 容错方式的偶尔性;而后给大家引见一下在块存储产品下构建 EC 引擎的应战,并逐渐开展对这些应战启动剖析和处置的方法;最后,咱们引见一下基于这个处置打算的一些优化。
首先引见一下经常出现的数据容错方式。
数据容错在单机和散布式系统下,有着不同的决定。
单机状况下,比拟间接的方式是决定 RAID 卡。在 BIOS 中性能,普通支持 RAID5 就够了。假设没有 RAID 卡,也可以用软 RAID,创立带有 RAID 性能的逻辑卷。
散布式的状况,比拟间接的方式是驳回多正本的方式,将数据复制成多份,存在不同的机器。实践上,最好将每份数据保留到不同的替换机下。另外一种方式是驳回散布式纠删码的方式。这种方式其实就是散布式的 RAID。只不过,单机用奇偶校验的 RAID5 基本可以保障数据安保,而散布式系统中,由于磁盘规模庞大,纠删码的复杂度要高一些。
这里引见一下散布式容错方式的成功。多正本方式容错,每个正本的数据相反,所以,普通驳回散布式的分歧性协定对数据启动同步,干流的协定为 Paxos 和 Raft。有的系统也会自研一些散发写的协定。最终目的是保障多份数据相反。多正本状况下,假定是 N 正本,则最多准许 N-1 份数据损坏。
纠删码则是将用户的原始数据启动切分,构成 K 个大小相等的分片,而后对这些分片启动编码,构成 M 个校验分片。校验分片的大小和数据分片相反。K+M 个分片会被散布在不同的机器上。普通状况下,纠删码准许最多 M 个分片数据损坏。最罕用的纠删码是 Reed-Solomon 编码(RS 码);
从老本思考,3 正本将数据存储 3 份,因此是 3 倍的存储老本。而纠删码,是 K+M 的方式,K 份的数据,编码构成 M 份校验。通常状况下,M 比 K 要小。因此存储老本普通为 1.x 倍。
然而,纠删码也有自己缺陷。多正本将数据无修正地复制到另外节点,不须要计算介入,数据复原则是将数据从新复制一遍,方法比拟繁难。而纠删码则触及到编码和解码,除了计算以外,编码和解码雷同会带来额外的I/O 开支。
现代 CPU 曾经支持 RS 编码的配件减速,能够优化编码/解码速度,极大缩小计算压力。而 I/O 加大,则是咱们重点要处置的疑问。
磁盘通常具备 1%~2%的年化缺点率。由于散布式系统规模都比拟大,大的集群都会有千台机器,万块磁盘的规模,肯定会同时出现多块磁盘同时缺点。因此,普通散布式系统都驳回 2 个以上的备份或许校验。普通驳回 3 正本或许 RS 编码能力保障数据的牢靠性。基于目前的集群规模和老本,纠删码是肯定的决定。
2.大规模块存储 EC的技术应战
既然决定了纠删码,上方那肯定处置 EC 系统中面临的各种疑问。
系统面临的应战关键来自几个方面。一个是产品访问个性,块存贮存储的是灵活数据,用户会随时对数据启动修正。而 EC 修正代价高,原地修正须要引入额外计算和 I/O 加大。
另外就是用户下发给磁盘的数据大小不一,而小写不适宜 EC。如何处置小 I/O 的 EC,是另外一个疑问。
运行场景上,用户对大小写的要求是不一样的。因此,咱们的设计须要一个正当的系统开支,缩小资源占用,使得用户有比拟好的 I/O 体现。
对比一下对象存储。它对外的接口是 put、get、delete。写入时,将一个对象的全体数据全体写入和全体删除,不触及到从新编码的疑问。因此,除了写入时发生的校验数据须要保留,没有其他写加大疑问。
块存储,关键接口是读写和删除。与对象存储不同,这里的写绝大局部是对原有数据的修正。
关于局部数据修正,假设从新计算校验,须要将残余数据从其他节点读到内存中,从新计算校验值,而后将校验再次写回。这里触及到了「读-修正-写」,I/O 加大比拟重大。
这里是线上 I/O 次数统计,小 I/O 的次数远远多于大 I/O。块存储 CDS 中,4K 大小的 I/O 占据了半数以上的写次数。然而小 I/O 不太适宜 EC。
举个例子:咱们假设驳回 K 为 4,M 为 2 的编码,须要将分片切成 1K 大小,而普通状况下,文件系统关于 4K 倍数的 I/O 支持比拟友好,1K 的 I/O size,相对来说,不是很正当的 I/O size。假设 K 值更大,会发生更细碎的分片。咱们须要处置这些小 I/O 的 EC。
现代软件曾经对磁盘访问有比拟多的优化。当程序谋求吞吐时会下发大 I/O,缩小磁盘寻道期间。当程序对延时有需求时,通常会下发尽量小的 I/O,缩小不用要的数据对 I/O 带宽的占用。
因此,总体看来,关于小 I/O用户须要的是小的延时,关于用户大的 I/O 用户须要的是高的吞吐。
配件的物理带宽是有限的,提供高性能的存储引擎,系统自身占用的资源应该尽量小。关于存储引擎来说,关键就是写加大疑问。
针对以上疑问,咱们看一下百度桑田的处置打算。
这里咱们从新看一下修正,I/O 加大的关键要素是须要对原有存量数据启动修正操作,假设不做不凡优化,这些操作须要将原有数据读进去,用于计算新的校验。
CDS 的决定是构建一个索引层,索引指向 EC 后的数据,数据的修正不在原地启动。
这里给了个例子,用户第一次性写的数据,EC 并且存储后,建设了一个索引指向这块数据。后续在两边的修正将作为一个新数据启动 EC 并且存储。而后构建新的索引指向新的数据,之前的索引决裂成 2 局部。
这样做后,咱们实践上建设了一个基于 EC 数据的 Append 引擎。EC 后的数据,对应的就是 Append 引擎中的 segment。一切的修正驳回追加写的方式,同等于 append 引擎的单路追加写。
实践上,CDS 并未从头开局设计一个 EC 系统,而是驳回了公司内成熟的 EC 系统 Aries 作为底层贮存介质,Aries 是百度桑田提供的特意低劣的 EC 系统和数据底座。写入 Aries 的数据将作为一个 slice 存储,而一个 slice 可以对应到逻辑层的一个 segment。
咱们前面提到了须要处置用户小写 EC 的疑问。可以驳回的一个打算是建设一个三正本的存储层,用来缓存用户 I/O。当用户写满肯定规模的数据时(比如:1GB),将这些数据 EC 后启动存储。
这样的好处是一切写数据混在一同启动存储,分片的切分可以依据 EC 规模启动决定,可以做到分片对 I/O 友好。其中,EC 层基本可以假定分片是固定大小的。
然而,这么做的缺陷也很显著。数据会被先写到 3 正本层,再写到 EC 层。肯定会有多于 4 倍的 I/O 加大。咱们也统计了线上数据的写入量,数据量占据比拟多的是大 I/O。这些大 I/O 对 EC 相对比拟友好,可以驳回间接 EC 的方式启动。
百度桑田的打算是将大写和小写启动区分处置。大写间接启动 EC,小写驳回 3 正本方式存储。
这样做的好处是,大写的数据不经过 3 正本层,规避了缓存带来的绝大少数 I/O 加大。3 正本关键存储小 I/O,由于占比小,所以对老本的压力增长不是很大,I/O 加大也不是很重大。
系统成功时,预留了 10%作为 3 正本存储空间。3 正本也驳回 append 引擎启动存储。数据 compaction 时,间接将数据存储到 EC 层。
这种设计,当 3 正本层空间弛缓时,数据依然会被启动 EC 存储,能够在用户都是小 I/O 的极其状况下,依然有不错的老本体现。
外部交流时,经常会被问到数据能否会从 EC 层转移到 3 正本层。假设是同种介质,咱们假定访问延时没有变动。因此,不将 3 正本层作为缓存层。
大 I/O 并不是固定大小,系统决定将大 I/O 间接 EC 的状况下,关于底层 EC 的存储引擎有新的要求。它肯定能够处置不同大小的分片。
设计难点是,监禁的空间如何被回收应用。图中给了个例子,当数据比空泛大时,不可将数据放入;当数据比空泛小时,形成空间糜费。因此,高层存储应该驳回能够很好顺应变长分片的引擎。
EC 存储引擎层依然驳回 append 写的方式。新数据 append 写,严密陈列在存储系统的后端。这样,新数据的空间调配变的繁难。
相关于原地写,append 写无论是关于 ssd 还是 hdd,性能都更好,这也为高性能存储打下了基础。
因此,总体架构是一个双层 append 架构。第一层有一个逻辑的 append 引擎,每个 EC 数据对应一个逻辑 segment。高层物理层存储 EC 的分片,也驳回 append 的方式,数据只启动追加写。
咱们经过两层架构处置了修正加大,大小写如何 EC 的疑问。然而,依然须要进一步提高系统性能,优化用户体验。
由于系统总带宽固定,假设 compaction 占用的带宽过大,留给用户经常使用的带宽就会降低,影响用户体验。
Append 引擎的一个关键评估目的,就是 I/O 加大,即系统总的物理 I/O 除以用户的 I/O。
要成功比拟低的 I/O 加大,咱们须要了解用户数据的访问特色。依据用户数据的访问特色,启动有效优化。
普通来说,用户的数据访问都存在热点状况。即最近写过的数据,被再次写的概率更大,也合乎齐夫散布的特色。
齐夫散布,如公式所示,r 为访问频率的排名。C 和⍺为常数。即排名越往后,访问频率越低。对这个公式同时取对数的状况下,是一个降低的直线。咱们也对线上数据的写频率启动了统计。除了长尾外,前半局部排名的数据,基本合乎齐夫散布。
假设依照访问期间启动统计,那么 1 天内有写的热数据,只占总数据的 5%左右。
既然数据有冷热,那么当咱们决定 segment 启动 compaction,就可以应用数据的这种访问特点启动。
普通的决定方法是贪心算法,即决定最空的 segment 启动 compaction。如图中的例子,在贪心算法的状况下,由于 segment B 的空泛率更高,会决定 segment B 启动 compaction。然而,由于 B 中的数据比拟新,很有或许是热数据,则这些数据过很小的一段期间就或许被笼罩写。这次数据搬将就显得多余。
思考到 segment A 中数据比拟老。依照用户访问特点,更老的数据被降级的或许性更小。Segment A 会被常年占用,空泛空间不可监禁。实践上,这些空泛更有价值,由于一旦监禁,能够被应用很常年间。所以,cost-benefit 算法统筹了空泛率和数据年龄。它的 pick 算法如公式所示,其中 u 代表有效数据率,age 示意 segment 中最新数据的年龄。这样,空泛率比拟高的的 segment 会被选中,老的 segment 也有大略率被选中,监禁出更有价值的空泛。
另外,compaction 的数据和用户的写入数据雷同有不同的冷热。通常 compaction 的数据为常年间没有写到的数据。将这些数据独自分流,能够构成较为稳固的 segment。而用户的写入的数据短期间内被写的或许性比拟大,也独自搁置。这样启动分类后,能够构成一些致密的 segment,寄存老数据。频繁的写入构成一些稠密的 segment,这些 segment 可以被重复应用。
假构想要更好的成果,可以将数据流划分更细,更多地缩小写加大。
咱们统计了线上统计访问,启动回放,控制不同物理空间经常使用状况下,验证了写加大的优化成果。
从图中可以看出,cost-benefit 与贪心算法相比,能够有效缩小写加大。在空中间占用率的状况下(如 95%),cost-benefit 方式,能够到达 1.5 以下的写加大。而贪心算规律要到达 4 倍以上。
另外,更多的分流能够缩小写加大。在贪心算法的状况下,能够节俭较多的 I/O。cost-benefit 状况下,4 路到 6 路收益不太显著。
另外可以看出,空间经常使用率对写加大也有影响,即较低的空间经常使用率的状况下,写加大更好。这也合乎直觉,compaction 越晚出现,segment 构成的空泛越多。
关于多层 append 系统,每一层都希冀把本层能用的空间尽量用满,而后再做 compaction。然而这么做会造成下一层的空间继续弛缓,造成高层写加大比拟重大。例如,假设逻辑层写的比拟满,迟迟不做 compaction,那么物理层则须要频繁做 compaction 为逻辑层提供短缺写空间。
系统的全体写加大,应该是每一层的写加大的乘积。那么,总体写加大并不是谋求单唯一层低写加大,而是一个平衡的写加大,使得全体写加大较低。
因此,咱们联合自己的系统特色,设计了一个平衡 compaction 的点。最高层是用户数据空间,高层是 EC 系统能够提供的物理空间,两边是写入 EC 层的数据。
咱们决定一个两边点启动 compaction 的决定,假设这个点偏左,说明高层数据比拟致密,空泛较少,则高层启动 compaction。假设这个点偏右,则说明高层致密,高层空泛率较多,触发高层的 compaction。
这样,咱们就构成了一个灵活可调理的 compaction 点,使得上高层的 compaction 都不太大,灵活保养一个较低的全体 compaction。
总结上去,系统有低老本的需求,大规模场景下多正本由于老本疑问,不能满足需求。因此,咱们必要驳回纠删码的方式组织数据。
而纠删码自身修正代价比拟大,系统设计当中,应用追加写的方式启动修正。并且驳回大小写分别的方式存储数据。分别后,大写局部发生的 EC 数据为变长,驳回 append 的引擎,为这种变长分片提供更好的空间调配机制,同时能够充沛应用配件追加写的性能优势。
综上,百度桑田的块存储驳回了 2 层 append 打算,规避了 EC 的修正代价。经过大小写分别状况,处置了小写不适宜 EC 的状况。同时决定了适宜 pick 算法、数据分流、适宜的 compaction 点的方式,优化了系统的写加大,能够到达低老本下较高的系统性能。
以上是当蠢才享的所有内容。