在分布式存储系统的设计中,复制(Replication)与纠删码(Erasure Coding)代表了容错机制的两种极端。复制方案将完整数据存储于多个节点,读取任一节点即可获得全部内容;而纠删码则将数据切分为若干片段,通过数学编码实现 "任意 k 个片段即可重建原始数据" 的容错能力。当纠删码遇上分布式共识中的法定人数(Quorum)机制时,一个核心问题浮现:并非所有字节都需要参与投票,但如何确保非全量参与时的数据完整性?
从全量复制到选择性参与
传统法定人数系统建立在复制模型之上:每个节点存储完整数据副本,读写操作只需获取足够数量的节点 "投票" 即可。根据 Naor 与 Wool 的经典定义,法定人数系统的核心属性是任意两个法定人数的交集非空—— 这一属性确保了互斥性和一致性。
然而,纠删码改变了游戏规则。在 (n, k) MDS(Maximum Distance Separable)码中,原始数据被编码为 n 个块,其中 k 个数据块(data chunks)和 n-k 个校验块(parity chunks)。任意 k 个块即可重建原始数据,但没有任何单个节点存储完整信息。这意味着传统的 "节点即副本" 思维不再适用。
关键洞见在于:数据块与校验块在更新语义上扮演不同角色。数据块彼此独立,更新一个数据块不影响其他数据块;但校验块是全部数据块的线性组合,任何数据块的变更都必须反映到相关校验块上。这一不对称性要求法定人数的设计必须显式区分数据节点与校验节点。
交集约束与完整性验证
在纠删码法定人数系统中,核心约束被强化为:任意两个法定人数的交集必须包含至少一个校验节点。这一约束(记为性质 4)比传统法定人数的 "非空交集" 要求更严格,其必要性体现在两方面:
首先,校验节点是更新传播的媒介。当写入操作更新某个数据块时,它必须同时更新该法定人数包含的所有校验块。由于任意两个法定人数在校验节点处相交,后续读取操作通过交集的校验节点即可获知最新的数据版本,无需等待后台更新传播完成。
其次,这一设计支持降级读取(Degraded Read)。当存储目标数据块的节点不可用时,系统可通过读取其他 k-1 个数据块和至少一个校验块来重建数据。关键在于:参与重建的校验块必须包含目标数据块的最新版本信息。由于写入操作的法定人数包含了该数据块对应的所有校验节点,且任意读取法定人数与写入法定人数在校验节点处相交,因此总能找到至少一个 "知情" 的校验节点。
Grid Quorum 的工程实现
针对 (n, k) MDS 码,研究者提出了 Grid Quorum 布局方案。将 n 个节点排列为 √n × √n 的方阵,数据块置于下三角(含对角线),校验块置于上三角。在此布局下,法定人数被定义为 "第 i 行与第 i 列的并集",其大小为 2√n - 1。
这种设计满足所有约束条件:
- 任意两个法定人数在 (i, j) 和 (j, i) 处相交
- 当 i <j 时,(i, j) 位于上三角,是校验节点
- 当 j <i 时,(j, i) 位于上三角,同样是校验节点
因此,任意两个法定人数的交集必然包含至少一个校验节点,满足性质 4。
** 截断变体(Truncated Variant)** 进一步优化了法定人数大小。标准 grid quorum 的每个法定人数包含整行和整列,而截断版本仅包含目标数据节点所在行 / 列的校验节点部分。这使得法定人数大小从 2√n - 1 降至约 √n,同时保持交集属性不变。
负载均衡的工程权衡
纠删码法定人数系统面临一个固有挑战:校验节点成为负载热点。在均匀访问策略下,存储于位置 (r, c) 的校验节点属于 r + c 个法定人数,而数据节点通常只属于 1-2 个法定人数。根据负载定义( busiest 节点的访问概率),校验节点的负载显著高于数据节点。
这一负载不均衡在实际系统中产生以下影响:
读取路径:对于正常读取(目标数据节点可用),I/O 操作主要集中在数据节点,校验节点仅参与 "投票"(互斥锁管理)。此时负载不均衡对性能影响有限。
写入路径:写操作必须更新法定人数内的所有校验块,校验节点需要执行编码计算和磁盘写入。当写入负载较高时,校验节点可能成为瓶颈。
降级读取:当数据节点不可用时,需要通过校验节点重建数据,此时校验节点既要参与投票,又要提供编码数据,负载进一步加剧。
实践中,纠删码通常用于冷数据存储(如 Backblaze B2、Facebook f4),这类场景写入频率较低,校验节点的负载压力相对可控。
可落地的配置参数
基于上述分析,以下是工程实现中的关键参数与检查清单:
编码配置:
- 高 durability 场景:17+3(Backblaze B2),存储开销 1.18x,容忍 3 节点故障
- 平衡场景:8+4(OVH Cloud),存储开销 1.5x,容忍 4 节点故障
- 低延迟场景:6+3(Scaleway),存储开销 1.5x,容忍 3 节点故障
法定人数大小:
- 标准 Grid Quorum:2√n - 1 个节点
- 截断 Grid Quorum:约 √n 个节点(仅包含目标数据节点和相关校验节点)
- B-Grid 扩展:支持 n = cbr 布局,法定人数大小为 br + c - 1
一致性保证:
- 读法定人数 R 与写法定人数 W 需满足 |R ∩ W| ≥ k
- 任意两个法定人数的交集必须包含至少一个校验节点
- 降级读取时,确保参与重建的校验块包含目标数据块的最新版本
故障容忍:
- 可容忍 n - k 个节点同时失效
- 当单个数据节点失效时,需要至少一个 "知情" 校验节点参与重建
- 当多个数据节点失效时,需要相应数量的校验节点参与重建,且这些校验节点反映相同版本的其他失效数据块
实现注意事项
在实际系统实现中,还需考虑以下工程细节:
版本管理:每个节点需要存储逻辑时间戳以标识最新版本,同时保留旧版本直至更新传播完成,用于支持降级读取时的版本对齐。
后台更新:法定人数内的校验节点同步更新,法定人数外的校验节点通过后台任务异步更新。这引入了短暂的 "部分更新" 状态,但通过交集约束确保一致性。
编解码开销:Reed-Solomon 编码的复杂度为 O (k (n-k)),解码时若需要使用校验块,需解线性方程组,开销随所需校验块数量增加而增加。Intel ISA-L 等 SIMD 优化库可将性能提升数倍。
布局映射:逻辑 grid 布局需映射到物理节点,考虑网络拓扑和数据局部性。数据块与校验块的物理分布应尽可能均匀,避免机架级故障导致数据不可恢复。
总结
纠删码与法定人数共识的结合展示了分布式系统中 "非全量参与" 的设计智慧。通过强制要求法定人数交集包含校验节点,系统在保持较低存储开销的同时,实现了顺序一致性和降级读取能力。这一设计并非没有代价 —— 校验节点的负载集中、写操作的编码开销、降级读取的计算成本 —— 但对于冷数据存储场景,这些权衡是可接受的。
核心设计原则可概括为:数据节点承载内容,校验节点承载共识。在工程实现中,理解这一角色分工,合理配置编码参数和法定人数大小,是构建高可靠、低成本分布式存储系统的关键。
参考来源:
- Oggier, F., & Datta, A. (2021). On Grid Quorums for Erasure Coded Data. Entropy, 23(2), 177. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7911346/
- Transactional.blog (2024). Erasure Coding for Distributed Systems. https://transactional.blog/blog/2024-erasure-coding
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。