1.背景

理论分析和本人之前的测试都表明,NVME SSD的峰值性在始终一路IO流追加写的情况下能够达到。通常分布式存储里,一个磁盘上可能有多个复制组,每个复制组一路IO流(忽略append entry和write data个步骤的IO),这样在普通的NVME SSD磁盘上无法打满磁盘性能。为此,需要把多路复制组的数据流合并一路。这就是需要实现追加写引擎。

此外,基于追加写的引擎在做快照的时候,可以基于ROW (Redirect on Write)而非COW(Copy on Write)去实现。当然如果沿用之前的COW策略,那么快照的写也需要基于追加写去实现。

追加写引擎牺牲读来换取写性能,以数据的规整性为代价,来迁就SSD盘对数据顺序写入的要求。对覆盖写的老数据占用的空间需要回收,逻辑地址不连续的数据需要规整,这就需要GC。

下面分析了追加写引擎设计和实现的几个要点。

2. 如何把不同复制组之间的乱序数据转顺序

总体来说就是:
2.1 改下所使用的分布式一致性协议中添加日志都接口,在这个接口里面接受所有不同复制组的读写请求;
找到所使用的分布式一致性协议实现写数据的append 一致性协议日志entry 的接口和类,继承该类,覆盖相关接口函数;

2.2 为每一个包含用户数据的分布式一致性协议日志中的用户数据建立索引逻辑地址到物理地址的索引:
逻辑地址包括:用户数据所落到的复制组ID、版本、切片编号、切片内偏移和数据长度
物理地址包括:分布式一致性协议日志写到物理磁盘或文件系统上的文件编号、偏移;

2.3 在分布式一致性日志同步到多数节点之后,在leader节点上把索引信息添加到所在的复制组下挂的数据block的extent 索引表中。

这个索引表和复制组之间的层次关系如下:
* 1个复制组下挂多个数据切片;
* 每个数据切片有多个版本;
* 每个版本的数据有一个索引信息表;
* 索引信息表里的每一项纪录上面每一个逻辑地址到物理地址的映射信息;

3. 如何持久化索引

如果索引信息不持久化,进程重启之后可能会丢数据,因此需要持久化索引信息。和其他文件系统类似,索引信息可以周期地落盘,也可以通过额外的设计立即落盘。

如果使用周期落盘,可以考虑在分布式一致性协议周期做snapshot的时候落盘。

4. 如何选择可以被GC的数据

因为之前有博文讨论过f2fs的GC策略,这里不重复,只讨论如何选择哪些数据可以做GC。

GC的数据要求这些数据的索引信息已经持久化,如果没有这个限制,可能会有数据一直在被反复GC, 这个时候它的最新的索引信息可能一直无法落盘,掉电或者进程重启后它的索引信息就彻底丢失了,这样就会出现数据找不到的问题。

基于上面的要求,在分布式系统多个复制组一路写入的情况下,要做GC的时候就得找出那些物理数据切片,这个切片上上的所有的数据的索引都已经持久化。

为此,上面建立索引的时候,需要添加相应的纪录来跟踪记录哪些物理数据切片上的数据已经持久化。

如何保证选择GC的数据和GC 删数据过程的均衡