Loading

OPPO F2FS 增量压缩存储方案

演讲链接:第 17 届中国 Linux 内核开发者大会 IO 与 eBPF 分论坛-CSDN 直播

image

数据库会带来大量随机更新写

对 F2FS 来说,一次写不仅需要更新 data block,还需要更新索引 block(direct node block),以及 Node Address Table。

这带来的写放大是很可怕的,假如只更新几十个字节,一共需要写入 3 * 4KBytes。

image

增量压缩只记录 diff,而不是更新整个 block。读取的时候需要依赖 base 和 diff

增量压缩不需要更新原数据,避免了更新 direct node。

image

image

Diff 记录在哪?对于 3.69K-3.69M 的 inode,内联区域部分为空,可以记录在内联区域中。

3.69K:能内联的最大大小,923slot * 4Bytes/slot。

3.69M:内联区域有额外空间的最大大小,923slot * 1addr/slot * 4KBytes/addr。inode 大于 3.69 M 时,内联区域全部存放 block addr。

image

图有点复杂,总结下 IO 流程:

Read:

  1. 读 inode page 和其他索引 node page
  2. 读 data page
  3. 解压 inode page 中的 diff,与 data page 运算得出最终数据。

Write:

  1. 读 inode page 和其他索引 node page
  2. 读 data page,并复制一份(Base data)
  3. 新数据写入 data page(New data)
  4. New 与 Base 运算,得出 diff,压缩,写入 inode page

image

演讲中提到,增量压缩数据有两种存放形式:

  1. 非固定大小:记录 ① diff 所属的 page index ② diff size ③ diff 内容。
  2. 固定大小:记录 ① diff 所属的 page index ② 最大 4K 的 diff。

固定少一个 diff size 开销,但容易有碎片。

image

这个公式其实说的是:当新的 diff 进来但没有空间时,逐出旧 diff or 采用普通写入的取舍问题。

这里总结下我能想到的 diff 逐出情况。

非强制逐出 diff 策略:

  1. GC 时,inode 和 data 都被读到内存,再写回磁盘。这个过程可以把 diff 刷回 data 中。没有额外开销,不过触发频率得不到保证。
  2. Write data 时,如果 inode 中属于此 data 的 diff 条目过多/数量过大,可以切回普通写入并刷入磁盘。同样没有额外开销(只关注 I/O,解码忽略不计),但失去了增量写入的优势。

强制逐出 diff 场景:

  1. i_size 增大,需要更多空间保存 data blkaddr:只能强制逐出,代价相当于一次普通写入。
  2. 新产生的 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 时,逐出收益较高,反之应该直接写入。

image

image

image

image

image

截至 22/10/26,没有公开源码。

posted @ 2022-10-27 18:07  liuchao719  阅读(759)  评论(0编辑  收藏  举报