HDFS 纠删码

目的

复制成本高昂 - HDFS 中默认的 3x 复制方案在存储空间和其他资源(例如网络带宽)中具有 200% 的开销。但是,对于 I/O 活动相对较低的温数据和冷数据,在正常操作期间很少访问其他块副本,但仍会消耗与第一个副本相同数量的资源。

因此,一个自然的改进是使用纠删码 (EC) 代替复制,它以更少的存储空间提供相同级别的容错能力。在典型的纠删码 (EC) 设置中,存储开销不超过 50%。EC 文件的复制因子没有意义。它始终为 1,并且无法通过 -setrep 命令更改。

背景

在存储系统中,EC 最显著的用法是廉价磁盘冗余阵列 (RAID)。RAID 通过条带化实现 EC,它将逻辑顺序数据(例如文件)划分为更小的单元(例如位、字节或块),并将连续单元存储在不同的磁盘上。在本指南的其余部分中,此条带化分布单元称为条带化单元(或单元)。对于原始数据单元的每个条带,都会计算并存储一定数量的奇偶校验单元,此过程称为编码。可以通过基于幸存数据和奇偶校验单元的解码计算来恢复任何条带化单元上的错误。

将 EC 与 HDFS 集成可以提高存储效率,同时仍提供与基于传统复制的 HDFS 部署类似的数据耐用性。例如,一个具有 6 个块的 3x 复制文件将消耗 6*3 = 18 个块的磁盘空间。但使用 EC(6 个数据,3 个奇偶校验)部署,它仅消耗 9 个块的磁盘空间。

架构

在 EC 的上下文中,条带化具有几个关键优势。首先,它支持在线 EC(立即以 EC 格式写入数据),避免转换阶段并立即节省存储空间。在线 EC 还通过并行利用多个磁盘主轴来增强顺序 I/O 性能;这在具有高端网络的群集中尤其可取。其次,它自然地将小文件分布到多个 DataNode,并且无需将多个文件捆绑到单个编码组中。这极大地简化了文件操作,例如删除、配额报告以及联合命名空间之间的迁移。

在典型的 HDFS 群集中,小文件可以占总存储消耗的 3/4 以上。为了更好地支持小文件,在此项工作的第一个阶段,HDFS 支持带条带化的 EC。将来,HDFS 还将支持连续 EC 布局。请参阅设计文档和对 HDFS-7285 的讨论以获取更多信息。

  • NameNode 扩展 - 条带化 HDFS 文件在逻辑上由块组组成,每个块组包含一定数量的内部块。为了减少这些附加块对 NameNode 内存消耗,引入了新的分层块命名协议。可以从其任何内部块的 ID 推断出块组的 ID。这允许在块组级别而不是块级别进行管理。

  • 客户端扩展 - 客户端读写路径经过增强,可在块组中的多个内部块上并行工作。在输出/写入路径上,DFSStripedOutputStream 管理一组数据流,每个流对应一个存储当前块组中内部块的数据节点。这些流主要以异步方式工作。一个协调器负责整个块组上的操作,包括结束当前块组、分配新块组等。在输入/读取路径上,DFSStripedInputStream 将请求的逻辑数据字节范围转换为存储在数据节点上的内部块范围。然后,它并行发出读取请求。在发生故障时,它会发出额外的读取请求以进行解码。

  • 数据节点扩展 - 数据节点运行一个额外的 ErasureCodingWorker (ECWorker) 任务,用于在后台恢复发生故障的纠删码块。发生故障的 EC 块由 NameNode 检测到,然后 NameNode 选择一个数据节点来执行恢复工作。恢复任务作为心跳响应传递。此过程类似于在发生故障时重新复制副本块的方式。重建执行三个关键任务

    1. 从源节点读取数据:使用专用线程池从源节点并行读取输入数据。根据 EC 策略,它将读取请求调度到所有源目标,并且仅读取最少数量的输入块进行重建。

    2. 解码数据并生成输出数据:从输入数据解码新数据和奇偶校验块。所有丢失的数据和奇偶校验块都一起解码。

    3. 将生成的数据块传输到目标节点:完成解码后,将恢复的块传输到目标数据节点。

  • 纠删码策略为了适应异构工作负载,我们允许 HDFS 集群中的文件和目录具有不同的副本和纠删码策略。纠删码策略封装了如何对文件进行编码/解码。每个策略由以下信息定义

    1. EC 架构:包括 EC 组中的数据块和奇偶校验块的数量(例如,6+3),以及编解码器算法(例如,里德-所罗门、异或)。

    2. 条带化单元的大小。这决定了条带化读写、缓冲区大小和编码工作等操作的粒度。

    策略的命名方式为编解码器-数据块数量-奇偶校验块数量-单元大小。目前,支持五种内置策略:RS-3-2-1024kRS-6-3-1024kRS-10-4-1024kRS-LEGACY-6-3-1024kXOR-2-1-1024k

    还支持默认的REPLICATION方案。它只能在目录上设置,以强制目录采用 3x 副本方案,而不是继承其祖先的纠删码策略。此策略使得可以将 3x 副本方案目录与纠删码目录交错使用。

    REPLICATION 始终处于启用状态。在所有 EC 策略中,RS(6,3) 默认处于启用状态。

    与 HDFS 存储策略类似,纠删码策略在目录上设置。创建文件时,它将继承其最近祖先目录的 EC 策略。

    目录级 EC 策略仅影响在目录内创建的新文件。一旦创建文件,可以查询其擦除编码策略,但不能更改。如果将擦除编码文件重命名为具有不同 EC 策略的目录,则该文件将保留其现有的 EC 策略。将文件转换为不同的 EC 策略需要重写其数据;通过复制文件(例如,通过 distcp)而不是重命名文件来执行此操作。

    我们允许用户通过 XML 文件定义自己的 EC 策略,该文件必须包含以下三个部分

    1. layoutversion:这表示 EC 策略 XML 文件格式的版本。

    2. schemas:这包括所有用户定义的 EC 架构。

    3. policies:这包括所有用户定义的 EC 策略,每个策略都包含架构 ID 和条带单元(cellsize)的大小。

    Hadoop conf 目录中有一个名为 user_ec_policies.xml.template 的示例 EC 策略 XML 文件,用户可以参考该文件。

  • 英特尔 ISA-L 英特尔 ISA-L 代表英特尔智能存储加速库。ISA-L 是专为存储应用程序设计的优化低级函数的开源集合。它包括针对英特尔 AVX 和 AVX2 指令集优化的快速块里德-所罗门型擦除码。HDFS 擦除编码可以利用 ISA-L 来加速编码和解码计算。ISA-L 支持大多数主要操作系统,包括 Linux 和 Windows。ISA-L 默认情况下未启用。有关如何启用 ISA-L 的说明,请参见以下说明。

部署

群集和硬件配置

擦除编码对群集在 CPU 和网络方面提出了额外要求。

编码和解码工作会消耗 HDFS 客户端和 DataNode 上的额外 CPU。

擦除编码至少需要群集中与配置的 EC 条带宽度一样多的 DataNode。对于 EC 策略 RS (6,3),这意味着至少需要 9 个 DataNode。

擦除编码文件也跨机架分布以实现机架容错。这意味着在读取和写入条带文件时,大多数操作都在机架外。因此,网络二分带宽非常重要。

对于机架容错,拥有足够数量的机架也很重要,这样平均每个机架容纳的块数不超过 EC 校验块数。计算此数量的公式为 (数据块 + 校验块) / 校验块,向上取整。对于 EC 策略 RS (6,3),这意味着至少需要 3 个机架(通过 (6 + 3) / 3 = 3 计算),理想情况下需要 9 个或更多机架来处理计划内和计划外中断。对于机架数量少于校验单元数量的集群,HDFS 无法维持机架容错,但仍会尝试将条带文件分散到多个节点,以保留节点级容错。因此,建议设置拥有相似数量数据节点的机架。

配置密钥

默认情况下,所有内置擦除编码策略都已禁用,除了在 dfs.namenode.ec.system.default.policy 中定义的策略,该策略默认启用。集群管理员可以通过 hdfs ec [-enablePolicy -policy <policyName>] 命令根据集群大小和所需的容错属性启用一组策略。例如,对于拥有 9 个机架的集群,RS-10-4-1024k 这样的策略将无法保留机架级容错,而 RS-6-3-1024kRS-3-2-1024k 可能更合适。如果管理员只关心节点级容错,只要集群中至少有 14 个数据节点,RS-10-4-1024k 仍然合适。

可以通过“dfs.namenode.ec.system.default.policy”配置系统默认 EC 策略。使用此配置时,当在“-setPolicy”命令中未将策略名称作为参数传递时,将使用默认 EC 策略。

默认情况下,“dfs.namenode.ec.system.default.policy”为“RS-6-3-1024k”。

Reed-Solomon 和 XOR 的编解码器实现可以通过以下客户端和 DataNode 配置键进行配置:io.erasurecode.codec.rs.rawcoders(用于默认 RS 编解码器)、io.erasurecode.codec.rs-legacy.rawcoders(用于旧版 RS 编解码器)、io.erasurecode.codec.xor.rawcoders(用于 XOR 编解码器)。用户还可以使用如下配置键配置自定义编解码器:io.erasurecode.codec.self-defined-codec.rawcoders。这些键的值是带有回退机制的编码器名称列表。这些编解码器工厂按照配置值指定的顺序加载,直至成功加载编解码器。默认 RS 和 XOR 编解码器配置优先使用本机实现,而不是纯 Java 实现。没有 RS-LEGACY 本机编解码器实现,因此默认值仅为纯 Java 实现。所有这些编解码器都有纯 Java 实现。对于默认 RS 编解码器,还有一个本机实现,该实现利用英特尔 ISA-L 库来提高编解码器的性能。对于 XOR 编解码器,还支持利用英特尔 ISA-L 库来提高编解码器性能的本机实现。有关更多详细信息,请参阅“启用英特尔 ISA-L”部分。RS Legacy 的默认实现是纯 Java,而默认 RS 和 XOR 的默认实现是使用英特尔 ISA-L 库的本机实现。

还可以通过以下配置参数调整 DataNode 上的擦除编码后台恢复工作

  1. dfs.datanode.ec.reconstruction.stripedread.timeout.millis - 条带读取的超时时间。默认值为 5000 毫秒。
  2. dfs.datanode.ec.reconstruction.stripedread.buffer.size - 读取器服务的缓冲区大小。默认值为 64KB。
  3. dfs.datanode.ec.reconstruction.threads - Datanode 用于后台重建工作的线程数。默认值为 8 个线程。
  4. dfs.datanode.ec.reconstruction.xmits.weight - 与复制块恢复相比,EC 后台恢复任务使用的 xmits 的相对权重。默认值为 0.5。将其设置为 0 以禁用为 EC 恢复任务计算权重,即 EC 任务始终具有 1 个 xmits。擦除编码恢复任务的 xmits 计算为读取流数和写入流数之间的最大值。例如,如果 EC 恢复任务需要从 6 个节点读取并写入 2 个节点,则其 xmits 为 max(6, 2) * 0.5 = 3。复制文件恢复任务始终计为 1 个 xmit。NameNode 利用 dfs.namenode.replication.max-streams 减去 DataNode 上的总 xmitsInProgress,该 DataNode 结合了来自复制文件和 EC 文件的 xmits,以将恢复任务调度到此 DataNode。

启用 Intel ISA-L

HDFS 本机实现的默认 RS 编解码器利用 Intel ISA-L 库来改进编码和解码计算。要启用和使用 Intel ISA-L,需要三个步骤。

  1. 构建 ISA-L 库。有关详细信息,请参阅官方网站“https://github.com/01org/isa-l/”。
  2. 使用 ISA-L 支持构建 Hadoop。请参阅源代码中(BUILDING.txt)中的“Hadoop 构建说明”中的“Intel ISA-L 构建选项”部分。
  3. 使用 -Dbundle.isalisal.lib 目录的内容复制到最终 tar 文件中。使用 tar 文件部署 Hadoop。确保 ISA-L 在 HDFS 客户端和 DataNode 上可用。

要验证 Hadoop 是否正确检测到 ISA-L,请运行 hadoop checknative 命令。

管理命令

HDFS 提供了一个 ec 子命令来执行与擦除编码相关的管理命令。

   hdfs ec [generic options]
     [-setPolicy -path <path> [-policy <policyName>] [-replicate]]
     [-getPolicy -path <path>]
     [-unsetPolicy -path <path>]
     [-listPolicies]
     [-addPolicies -policyFile <file>]
     [-listCodecs]
     [-enablePolicy -policy <policyName>]
     [-disablePolicy -policy <policyName>]
     [-removePolicy -policy <policyName>]
     [-verifyClusterSetup -policy <policyName>...<policyName>]
     [-help [cmd ...]]

以下是每个命令的详细信息。

  • [-setPolicy -path <path> [-policy <policyName>] [-replicate]]

    在指定路径的目录上设置擦除编码策略。

    path:HDFS 中的目录。这是一个强制参数。设置策略仅影响新创建的文件,而不影响现有文件。

    policyName:要用于此目录下文件的擦除编码策略。如果设置了“dfs.namenode.ec.system.default.policy”配置,则可以省略此参数。路径的 EC 策略将使用配置中的默认值设置。

    -replicate 在目录上应用默认 REPLICATION 方案,强制目录采用 3x 复制方案。

    -replicate-policy <policyName> 是可选参数。它们不能同时指定。

  • [-getPolicy -path <path>]

    获取指定路径的文件或目录的擦除编码策略的详细信息。

  • [-unsetPolicy -path <path>]

    取消之前对目录调用 setPolicy 设置的纠删码策略。如果目录从祖先目录继承了纠删码策略,则 unsetPolicy 为无操作。对未设置明确策略的目录取消设置策略不会返回错误。

  • [-listPolicies]

    列出在 HDFS 中注册的所有(已启用、已禁用和已移除)纠删码策略。只有已启用的策略才适合与 setPolicy 命令配合使用。

  • [-addPolicies -policyFile <file>]

    添加用户定义的纠删码策略列表。有关示例策略文件,请参阅 etc/hadoop/user_ec_policies.xml.template。最大单元格大小在属性“dfs.namenode.ec.policies.max.cellsize”中定义,默认值为 4MB。目前,HDFS 允许用户总共添加 64 个策略,添加的策略 ID 在 64 到 127 的范围内。如果已经添加了 64 个策略,则添加策略会失败。

  • [-listCodecs]

    获取系统中支持的纠删码编解码器和编码器的列表。编码器是编解码器的实现。一个编解码器可以有不同的实现,因此有不同的编码器。编解码器的编码器按回退顺序列出。

  • [-removePolicy -policy <policyName>]

    移除用户定义的纠删码策略。

  • [-enablePolicy -policy <policyName>]

    启用纠删码策略。

  • [-disablePolicy -policy <policyName>]

    禁用纠删码策略。

  • [-verifyClusterSetup -policy <policyName>...<policyName>]

    验证集群设置是否支持所有已启用的纠删码策略。如果指定了可选参数 -policy,则验证集群设置是否支持给定的策略或策略。

限制

由于重大的技术挑战,某些 HDFS 操作(即 hflushhsyncconcatsetReplicationtruncateappend)不受纠删码文件支持。

  • 对纠删码文件执行 append()truncate() 将抛出 IOException
  • 如果将文件与不同的纠删码策略或与复制文件混合,则 concat() 将抛出 IOException
  • setReplication() 对纠删码文件无操作。
  • DFSStripedOutputStream 上的 hflush()hsync() 为无操作。因此,对纠删码文件调用 hflush()hsync() 无法保证数据持久化。

客户端可以使用StreamCapabilities API 查询 OutputStream 是否支持 hflush()hsync()。如果客户端希望通过 hflush()hsync() 实现数据持久性,当前的补救措施是在非纠删码目录中创建此类文件作为常规 3x 复制文件,或使用 FSDataOutputStreamBuilder#replicate() API 在纠删码目录中创建 3x 复制文件。