演讲链接:第 17 届中国 Linux 内核开发者大会 IO 与 eBPF 分论坛-CSDN 直播
数据库会带来大量随机更新写。
对 F2FS 来说,一次写不仅需要更新 data block,还需要更新索引 block(direct node block),以及 Node Address Table。
这带来的写放大是很可怕的,假如只更新几十个字节,一共需要写入 3 * 4KBytes。
增量压缩只记录 diff,而不是更新整个 block。读取的时候需要依赖 base 和 diff。
增量压缩不需要更新原数据,避免了更新 direct node。
Diff 记录在哪?对于 3.69K-3.69M 的 inode,内联区域部分为空,可以记录在内联区域中。
3.69K:能内联的最大大小,923slot * 4Bytes/slot。
3.69M:内联区域有额外空间的最大大小,923slot * 1addr/slot * 4KBytes/addr。inode 大于 3.69 M 时,内联区域全部存放 block addr。
图有点复杂,总结下 IO 流程:
Read:
- 读 inode page 和其他索引 node page
- 读 data page
- 解压 inode page 中的 diff,与 data page 运算得出最终数据。
Write:
- 读 inode page 和其他索引 node page
- 读 data page,并复制一份(Base data)
- 新数据写入 data page(New data)
- New 与 Base 运算,得出 diff,压缩,写入 inode page
演讲中提到,增量压缩数据有两种存放形式:
- 非固定大小:记录 ① diff 所属的 page index ② diff size ③ diff 内容。
- 固定大小:记录 ① diff 所属的 page index ② 最大 4K 的 diff。
固定少一个 diff size 开销,但容易有碎片。
这个公式其实说的是:当新的 diff 进来但没有空间时,逐出旧 diff or 采用普通写入的取舍问题。
这里总结下我能想到的 diff 逐出情况。
非强制逐出 diff 策略:
- GC 时,inode 和 data 都被读到内存,再写回磁盘。这个过程可以把 diff 刷回 data 中。没有额外开销,不过触发频率得不到保证。
- Write data 时,如果 inode 中属于此 data 的 diff 条目过多/数量过大,可以切回普通写入并刷入磁盘。同样没有额外开销(只关注 I/O,解码忽略不计),但失去了增量写入的优势。
强制逐出 diff 场景:
- i_size 增大,需要更多空间保存 data blkaddr:只能强制逐出,代价相当于一次普通写入。
- 新产生的 diff 保存不下,需要一进一出:将 inode 中的 diff 大小按 page index 累计,找出 diff 量最大 page,回写。然后把新的 diff 保存到 inode 中。 开销对比如下表,可以看到一进一出比普通写入多了一次读,这就要** diff 差量够大**,因而之后增量写入的收益大于此次逐出产生开销。
NAT | inode | 新写入数据的 data page | Diff 需要被逐出的 data page | |
---|---|---|---|---|
普通写入 | RW | RW | RW | - |
一进一出 | RW | RW | R | RW |
上图 PPT 说的是强制逐出的第二种场景。演讲中提到,oppo 根据埋点数据及理论推算计算出,在 diff 差量大于 81 KByte 时,逐出收益较高,反之应该直接写入。
截至 22/10/26,没有公开源码。
标签:存储,F2FS,逐出,inode,写入,diff,data,page,OPPO From: https://www.cnblogs.com/liuchao719/p/F2FS_incremental_compression.html