Skip to content

模型Model

RAID校验更新与写洞

RAID parity write hole · RAID 5 parity update · 校验阵列写洞

通过四盘异或校验计算擦除重建和更新I/O,枚举数据与校验的持久组合,展示部分写入如何破坏未改块,并界定日志与部分校验保护的能力。

条带与镜像用完整副本恢复丢失成员。另一种办法是为一组数据加一条校验方程:少一块时用其余块算回来。困难在于,修改数据时也要修改方程;两块各自能原子写入,不代表跨盘的两次更新能一起持久。

形式陈述 ​

三块数据加一块按位异或校验 ​

四盘每一行放三个数据块 X,Y,Z 和一个校验块 P,满足

P=X⊕Y⊕Z.

异或按块内同一位置的每一位执行。因为 a⊕a=0、a⊕0=a,已知X所在盘失效时,可由 X=P⊕Y⊕Z 恢复。恢复前提是校验与幸存数据来自一致的条带状态,且所有读到的幸存内容正确。

这种按位关系可看成二元线性码的单校验约束。它可以恢复一处已知擦除;若两块数据都未知,通常只有它们异或值的一个方程,不能唯一确定二者。未知位置的静默错误和已知擦除不同,也不因多一块校验就自动可纠正。

本页采用自定、明确的轮转布局:每条带恰有3个逻辑数据块,成员盘内行号 r=⌊b/3⌋,校验盘 p=(3−r)mod4;将其余三个盘号从小到大列出,第 bmod3 项存放逻辑块 b。这里chunk是1块,与前页2块chunk实验分开重置;不把这个公式冒充所有RAID5实现的唯一布局。

更新必须维护同一行的方程 ​

只将X改成 X′ 时,可使用读改写(read-modify-write):读旧X与旧P,计算

P′=P⊕X⊕X′,

再写X′与P′。另一个办法是读未修改的Y、Z,与X′重新求校验。无论采用哪个算法,最终稳定条带都应满足新方程;算法算对P′只是其中一步,跨盘持久化次序仍需单独处理。

直觉

校验是约束,不是另一份完整数据 ​

把数据项改动记成 Δ=X⊕X′。新校验就是旧校验异或 Δ,因此不必每次读完整条带来计算。但如果数据已经带上 Δ、校验还没有,恢复另一个缺失块时就会把 Δ 错误带进结果;校验看似还能参与运算,运算的前提却已失效。

轮转校验盘能避免每一行校验都压在同一个成员上。它没有增加每条带的独立方程数,也没有使跨成员写入变成一次原子操作。小写入成本与写洞是两个不同问题:前者数读写请求,后者检查掉电后哪些版本混在一起。

例子与边界

从布局到十六进制校验 ​

逻辑块8满足 r=2,bmod3=2,校验盘为1,其余成员是0、2、3,所以块8位于D3的盘内2。四盘每盘 C 块时,本布局提供 3C 数据块容量,不计元数据与备用空间。

现在只看第0行:D0、D1、D2是数据,D3是校验。每个256字节块只有第一个字节使用下列值,其余255字节全为0,因而可以完整手算且不遗漏块内异或的含义。

X=3C,Y=A5,Z=5A,P=3C⊕A5⊕5A=C3.

把X改成 0F,则 Δ=33,新校验为 C3 xor 3C xor 0F = F0。也可直接用 0F xor A5 xor 5A = F0 交叉核对。初始一致状态若丢失D1,C3 xor 3C xor 5A 恰好恢复 A5。

两读两写的计算口径 ​

假设无缓存命中、条带健康且各请求不合并,单块读改写需要读旧X与P两次,再写X′与P′两次,共4次成员数据块I/O;flush命令和元数据未计入。若本次一次性提供整行3个新数据块,可以直接算新P,写4块,不需要读取旧内容。

一般一次修改 k∈{1,2,3} 个数据块,读改写读 k 个旧数据加旧校验、写 k 个新数据加新校验,共 2k+2 次。按未改数据重新计算则读 3−k 块、写 k+1 块,总共4次。于是k=1两者同为4,k=2时为6对4,k=3时为8对4;完整条带写用后者即可。请求数不直接等于串行耗时,也不保证完整条带写能够原子持久。

一次未完成写怎样伤到从未修改的Y ​

假设初始 3C,A5,5A,C3 已可靠持久,包含Y=A5的旧文件内容早已确认成功。此次只请求把D0改为 0F,并给D3写新校验 F0;不向D1或D2写任何数据。允许两次成员写独立持久,每块本身不撕裂。

掉电时,D0的新值 0F 已持久,D3仍保留旧校验 C3,D1、D2仍是原值 A5,5A。因此真实数据异或为 F0,盘上校验却是 C3。此时若未先修复条带一致性就丢失D1,例如掉电后阵列已降级启动,用幸存三块重建得到

Y^=C3⊕0F⊕5A=96≠A5.

本次对X的写可能尚未确认,允许它丢失并不能解释Y被改成 96:Y完全没被这次请求修改,且旧值已确认。写洞破坏的是更新中数据与校验的一致性,随后重建可把损害传播到未修改块。

每一块原子并不保证跨盘同代
掉电后D0 掉电后D3校验 D1缺失时算得 与未改Y一致吗
旧 3C 旧 C3 A5 是
新 0F 旧 C3 96 否
旧 3C 新 F0 96 否
新 0F 新 F0 A5 是

只规定“先发数据写、再发校验写”还不够,设备可能重排持久顺序;即使中间做flush强制数据先持久,也仍保留新数据/旧校验的掉电窗口。需要能识别并修复跨代状态的协议,而不只是选一种下发顺序。

一次擦除保证不能覆盖额外读错 ​

若D1已经丢失,重建又读不到D2,则这一行出现两个已知缺失,单校验不足。若D2静默返回错误值,重建公式会把这个错误混入Y,即便没有写洞也不能保证正确。静态单盘擦除、部分持久写、重建读取错误必须分别列出;不能用“RAID5能坏一盘”省略其余前提。

推论与应用

保护恢复信息,再动条带成员 ​

一种教学修复可复用重做日志的after-image工具:先把新X和新P及目标成员地址记入可靠日志,持久提交日志后才修改成员;把两份成员更新都flush后,才清除日志。崩溃若留下已提交记录,幂等重做两份目标值,恢复一致的新行;未提交记录则不能伴随任何成员改写。

这个说明首先处理“掉电后日志仍可读、四个成员都可访问,并先完成恢复再接受后续失效”的模型。若掉电同时已有成员丢失,日志保存在哪里、能否随该盘一起丢失、如何在降级状态重做,都要另行证明。上层文件系统已经有日志,也不自动说明底层跨盘校验满足该协议;上层日志依赖的稳定逻辑块接口必须先由阵列兑现。

Linux MD的部分校验日志PPL针对另一种较窄目标:记录与未修改数据有关的恢复信息,避免不完整写入让未改块在降级恢复时损坏。它不把正在进行的用户数据写入变成完整事务,也不承诺保存所有未完成写。本例的未改部分异或为 A5 xor 5A = FF;额外保存这一约束与仅保留旧全行校验不是同一份信息,具体可恢复情形还取决于日志与失效盘位置。

复算终点应给出完整四格表、每次向哪些成员发了写、哪些值已经持久,以及恢复时哪些盘缺失。若只写一句“校验不一致”,读者还不能判断究竟损失了哪份此前正确的数据,也无法评价提出的恢复协议是否保护了它。

参考资料
关系图谱5 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

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