纠删码
背景
分布式系统的基本期望是提供数据持久性。为了提供更高的数据持久性,许多流行的存储系统采用了开销较大的副本机制。Apache Ozone 支持 RATIS/THREE 副本方案。Ozone 的默认副本方案 RATIS/THREE 在存储空间及其他资源(例如网络带宽)上会产生 200% 的开销。然而,对于 I/O 活动相对较少的温数据和冷数据集,在正常运行期间额外的数据块副本很少被访问,却仍然消耗与第一个副本相同数量的资源。
因此,一个自然的改进思路是用纠删码(Erasure Coding,简称 EC)替代副本机制,它能在大幅节省存储空间的前提下提供同等级别的容错能力。在典型的 EC 配置中,存储开销不超过 50%。EC 文件的副本因子是没有意义的。我们不再使用副本因子,而是引入了 ReplicationConfig 接口来指定所需的副本类型,即 RATIS/THREE 或 EC。
将 EC 与 Ozone 集成,可以在仍提供与传统基于副本的 Ozone 部署相似的数据持久性的同时,提高存储效率。举例来说,一个 3 倍副本、包含 6 个数据块的文件将占用 6*3 = 18 个数据块的磁盘空间。但采用 EC(6 个数据块 + 3 个校验块)部署时,它只会占用 9 个数据块的磁盘空间。
架构
存储数据布局是实现 EC 的关键因素。经过深入分析和技术考量,最合适的布局是条带(striping)模型。数据条带布局并不新鲜,条带模型此前已被其他几个文件系统成功采用(例如 Quantcast 文件系统、Hadoop 分布式文件系统等)。
例如,对于 EC(6 个数据块 + 3 个校验块)方案,数据块将按顺序分布到前 6 个数据节点,随后客户端生成 3 个校验块并按顺序传输给其余 3 个节点。这 9 个数据块合在一起称为"Stripe"(条带)。接下来的 6 个数据块将再次按顺序分布到同样的前 6 个数据节点,校验块则传输给其余 3 个节点。这 9 个节点上存储的数据块合在一起称为"BlockGroup"(块组)。
如果应用持续写入超过 6 * BLOCK_SIZE 的数据,客户端将向 Ozone Manager 请求新的块组。
纠删码写入
纠删码写入的核心逻辑位于 Ozone 客户端。当客户端创建文件时,Ozone Manager 会从管道提供者中分配 d + p 个节点作为块组,并返回给客户端。随着应用数据不断到来,客户端会先将前 d 个数据块写入块组中的 d 个数据节点,同时缓存这 d 个数据块以便生成校验块。校验块生成后,客户端会按顺序将其传输给其余的 p 个节点。当所有数据块都达到配置的大小后,客户端将请求新的块组节点。
下图描述了容器中以逻辑组为单位的块分配方式。出于篇幅考虑,图中假设采用 EC(3, 2) 纠删码配置。

让我们从上图中放大查看 blockID: 1 的数据布局,如下图所示。该图展示了数据块中 chunk 的排布方式。

目前,EC 客户端复用了现有的数据传输端点来向数据节点传输数据。用于写入数据和提交 putBlock 信息的是 XceiverClientGRPC 客户端。由于复用了现有的相同传输协议,数据节点端的改动很小。在数据节点上写入的 EC 数据块与非 EC 模式下的其他块完全相同。在一个块组内,所有节点上的容器 ID 都是相同的。一个文件可以包含多个块组。每个块组包含 d + p 个块,且所有 ID 都相同。
d — 一个块组中的数据块数量
p — 一个块组中的校验块数量
纠删码读取
读取时,OM 会在键查找过程中提供节点位置详情。如果该键采用纠删码编码,Ozone 客户端就会以 EC 方式读取它。由于数据布局不同(参见上一节关于写入路径的内容),读取时需要考虑该布局并据此进行读取。
EC 客户端会根据预期位置与数据节点(DN)建立连接。当所有数据位置都可用时,它会以轮询方式从 d 个数据块中逐 chunk 进行普通读取。
下图展示了读取过程中没有发生故障时的顺序。

在未出现读取故障之前,无需进行 EC 重构。
纠删码即时重构读取
当客户端在读取过程中检测到故障,或在开始读取时,Ozone EC 客户端能够通过 EC 解码来重构/恢复丢失的数据。要进行 EC 解码,它需要读取校验副本。由于需要进行重构,这属于降级读取。该重构过程对应用程序完全透明。
下图展示了在重构过程中如何使用校验副本。

纠删码副本配置
Apache Ozone 采用纯粹的「对象存储」语义构建。然而,大数据生态系统中的许多项目仍然使用文件系统 API。为了以最佳方式让两个世界都能访问 Ozone,Ozone 同时提供了这两种接口形式。无论采用哪种形式,键/文件在底层都会写入桶中。因此,可以在桶级别设置 EC 复制配置。EC 策略封装了文件的编码/解码方式。
每个 EC 复制配置由以下几部分信息定义:
- data: EC 块组中的数据块数量。
- parity: EC 块组中的校验块数量。
- ecChunkSize: 条带化分块(chunk)的大小。它决定了条带读写的粒度。
- codec: 用于指定 EC 算法的类型(例如
RS(Reed-Solomon)、XOR)。
要在命令行或配置文件中传递 EC 复制配置,需要使用以下格式:codec-数据块数量-校验块数量-EC 分块大小
目前支持三种内置的 EC 复制配置:RS-3-2-1024k、RS-6-3-1024k、RS-10-4-1024k。最推荐的选项是 RS-6-3-1024k。当创建键/文件而未指定复制配置时,如果其所属的桶具有 EC 复制配置,则会继承该配置。
更改桶级别的 EC 复制配置只会影响在该桶中新建的文件。文件一旦创建,目前无法更改其 EC 复制配置。
评论
登录后参与评论
KnowForge