Skip to content

算法Algorithm

日志段清理与写放大

LFS segment cleaning · 段清理 · Cleaning write amplification

按当前映射判定日志段中的活块,先复制并持久发布新地址再回收旧段,逐项核算净释放空间、数据写放大和含读取的清理成本。

日志结构文件系统把新版本写到新位置,旧记录逐渐失去引用。但“这段里大多是垃圾”不表示整段都能覆盖;只要还有一个被当前文件使用的块,直接复用全段就会删掉有效数据。段清理先救出活块,再把整片空间交回。

形式陈述 ​

判活对象是一个具体地址 ​

一个段有 S 个等大的数据记录槽,段摘要记录每槽对应的文件身份及逻辑块号。记当前映射为 M(f,b),给出文件 f 的逻辑块 b 所在的设备地址。段中地址 a 的记录对应 (f,b) 时,在单一当前版本模型里,它仍活当且仅当

M(f,b)=a.

“这个文件还存在”不够:它的同一逻辑块可能已在另一段更新。“这条记录版本号很大”也不够:必须与被保留版本实际使用的映射一致。文件编号可复用时,身份还要包含足以区分旧文件与新文件的代号,避免把同号新对象误认为旧对象。

本页先采用串行清理、无并发写者、无快照的模型。设某段仍活 L 块,活比例 u=L/S。清理必须先获得至少 L 块目标空间,复制活块并持久发布新映射,然后才允许把旧段全部 S 块释放;还要另外预留实际系统的元数据空间。

不变量贯穿复制和回收 ​

对每个仍活的逻辑块,清理前后读到的字节相同;发布的新地址已经持久;任何恢复仍可能选中的旧映射都不会指向被提前覆盖的块。旧段退役时,不得再有保留根或在途读者依赖它。复制完成只是这条顺序中的一步,不能替代映射发布与引用退出。

直觉

空间净增要扣掉搬家占用 ​

释放8块旧段之前,若已在别处用掉2块保存幸存数据,净获得的可用空间只有 8−2=6 块。只报“回收了8块”会高估下一批用户数据能写多少;只报“写了2块清理数据”又看不出为何系统需要预留空段才能继续前进。

小活比例往往意味着一次搬运能换到更多空闲空间,但“全盘用了多少”与“选中的段还活多少”是不同量。全盘可能大部分空间有用,同时仍有几段几乎全废;也可能到处都散落少量有效数据。清理政策需要看候选段,而不能直接把全盘占用率代入以下单段成本。

例子与边界

八个槽中只有两条仍被引用 ​

重置一个8数据槽的段,各槽内容如下。A:0表示文件A的逻辑块0,括号是帮助观察的记录版本标签,不作为独立判活依据。

槽 记录 当前是否活
0 A:0(旧1) 否,当前地址在其他段
1 A:1 是,当前映射仍指向本槽
2 B:0(旧1) 否,当前地址在其他段
3 C:0 否,C已删除
4 A:0(旧2) 否,其他段还有被当前映射选中的新版
5 B:0(旧2) 否,同上
6 D:0 否,当前地址在其他段
7 E:0 是,当前映射仍指向本槽

即使槽4比槽0新,两者仍都可能过期。逐条查当前地址后,只复制槽1与槽7,得到 L=2,u=1/4。新映射把A:1、E:0指向两块目标地址,完成持久发布与旧引用退出后才能释放整段。

8读、2搬移写、6新数据写使用同一个分母

4/3与8/3为什么不矛盾 ​

现在明确核算范围:只数等大数据块的读写,假设整段8块全部读入。段摘要、inode、imap、检查点、空闲索引、flush命令以及寻址成本都排除;因此这些数值不是实际设备的完整I/O账。

清理后净增6块空间,随后恰好写入6块全新的用户数据,构成一次完整“清理再填入”周期。两种比率使用同一个分母,即这6块新用户数据:

数据写放大=2(搬移写)+6(新写)6=43,总数据I/O比=8(读取)+2(搬移写)+6(新写)6=83.

若只统计清理阶段,读8加写2是10块I/O,除以净释放6得到 5/3;它没有包含随后那6块新写,与总周期 8/3 不同。原始LFS论文的“write cost”包括清理读取,在上述整段读取和忽略定位成本条件下对应后一个总I/O口径,不能仅凭英文名字把它当作纯写放大。

推导一般活比例 ​

对 0<u<1,复制占用 uS,净空闲为 (1−u)S。随后用净空闲写入同样数量的新用户数据,因此数据写量为 uS+(1−u)S=S,整段读取量也为 S,得到

WAwrite=11−u,CdataIO=21−u.

这里以块为单位时 uS 必须为整数。若 u=1,整段复制后净空闲为0,不能用它支撑下一批新写;分母为0表达的正是没有空间收益。若已可靠知道 u=0,可以完全不读旧段、直接复用,这时总I/O比可以降为1;强制整段读取的公式在零活块这一特殊路径上不再描述实际动作。

并发更新与快照会改变判活 ​

假设清理器读到 M(A,1)=旧地址 后,用户把A:1更新到第三个地址。清理器若随后无条件发布自己搬出的旧内容,就把用户的新写覆盖掉。一个并发实现必须在发布时核对映射仍是预期旧地址,或者用锁、事务等方法协调;“复制出的字节校验正确”并不能排除这类旧版本复活。

有快照时,最新根不再引用某槽,历史根仍可能引用。此时判活范围是所有必须保留的根,还要考虑尚未结束的读者。随意只查当前imap会把可读快照的数据清掉;反过来,保留所有历史记录永不回收又会耗尽空间。快照删除与回收的时点需要明确合同。

推论与应用

必须留出清理前的活动空间 ​

本例在回收旧段前先消耗2块目标空间。若池中一块可写空间都没有,即使某段75%已经过期,也不能用这套先复制后回收算法开始清理。保留空间、低水位触发和后台清理解决的是进展条件;它们不能省去可达性与持久顺序的安全条件。

低活比例只刻画当下的复制成本。频繁更新的数据以后可能自然失效,稳定冷数据搬过一次后却会长期占用目标段;按年龄和更新行为分组可能改变未来清理成本,但需要工作负载证据。当前公式没有证明“总选最小u”在所有未来序列上最优。

迁移练习:同样8槽改为6槽活。净空间只有2块,数据写放大为4,总数据I/O比为8;仍需先准备6块目标空间。把“净增2”与“启动需要6”同时写出,就能看见高占用时既更费I/O、又更难获得工作空间的双重约束。

参考资料
关系图谱3 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组