复制成本高昂——HDFS中默认的3倍复制方案在存储空间和其他资源(如网络带宽)上有200%的开销。然而,对于I/O活动相对较低的温数据和冷数据集,额外的块副本在正常操作中很少被访问,但仍消耗与第一个副本相同的资源量。
因此,一个自然的改进是使用纠删码(EC)替代副本机制,它能在显著减少存储空间的同时提供相同级别的容错能力。在典型的纠删码(EC)配置中,存储开销不超过50%。EC文件的副本系数没有意义,它始终为1且无法通过-setrep命令修改。
在存储系统中,纠删码(EC)最著名的应用是廉价磁盘冗余阵列(RAID)。RAID通过条带化技术实现EC,该技术将逻辑上连续的数据(如文件)划分为更小的单元(如位、字节或块),并将连续单元存储在不同磁盘上。在本指南后续内容中,这种条带化分配单元被称为条带单元(或单元)。对于每一条原始数据单元带,系统会计算并存储一定数量的校验单元——这个过程称为编码。任何条带单元上的错误都可以通过基于幸存数据和校验单元的解码计算来恢复。
将EC与HDFS集成可以提高存储效率,同时仍能提供与传统基于复制的HDFS部署类似的数据持久性。例如,一个具有6个块的3倍复制文件将消耗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管理一组数据流写入器,每个写入器对应存储当前块组中一个内部块的DataNode。这些写入器大多以异步方式工作。一个协调器负责整个块组的操作,包括结束当前块组、分配新块组等。在输入/读取路径上,DFSStripedInputStream将请求的逻辑字节数据范围转换为存储在DataNodes上的内部块范围,然后并行发出读取请求。遇到故障时,它会发出额外的读取请求进行解码。
DataNode扩展功能 - DataNode运行一个额外的ErasureCodingWorker(ECWorker)任务,用于后台恢复失败的纠删码块。NameNode会检测到失败的EC块,然后选择一个DataNode来执行恢复工作。恢复任务通过心跳响应传递。这个过程类似于副本块在失败时重新复制的方式。重建过程执行三个关键任务:
从源节点读取数据: 输入数据通过专用线程池从源节点并行读取。根据EC策略,它会调度所有源目标的读取请求,并且仅读取重建所需的最少输入块数。
解码数据并生成输出数据: 从输入数据中解码出新的数据和校验块。所有缺失的数据和校验块会被一起解码。
将生成的数据块传输到目标节点: 解码完成后,恢复的数据块会被传输到目标DataNode。
纠删码策略 为了适应异构工作负载,我们允许HDFS集群中的文件和目录采用不同的复制和纠删码策略。纠删码策略封装了如何对文件进行编码/解码。每个策略由以下信息定义:
EC模式: 这包括EC组中数据和校验块的数量(例如6+3),以及编解码算法(例如Reed-Solomon、XOR)。
条带化单元的大小。 这决定了条带化读写操作的粒度,包括缓冲区大小和编码工作。
策略被命名为编解码器-数据块数量-校验块数量-单元大小。目前支持五种内置策略:RS-3-2-1024k
, RS-6-3-1024k
, RS-10-4-1024k
, RS-LEGACY-6-3-1024k
, XOR-2-1-1024k
。
默认的REPLICATION
方案也受支持。该方案只能设置在目录上,强制目录采用3倍复制方案,而不是继承其祖先的纠删码策略。此策略使得可以将3倍复制方案的目录与纠删码目录交错使用。
REPLICATION
始终处于启用状态。在所有EC策略中,RS(6,3)默认启用。
与HDFS存储策略类似,纠删码策略是在目录级别设置的。当创建文件时,它会继承其最近祖先目录的EC策略。
目录级别的纠删码策略仅影响在该目录下新创建的文件。文件一旦创建后,其纠删码策略可以被查询但无法更改。如果将采用纠删码的文件重命名到具有不同EC策略的目录中,该文件仍会保留原有的EC策略。要将文件转换为不同的EC策略需要重写其数据,这应通过复制文件(例如使用distcp)而非重命名来实现。
我们允许用户通过XML文件自定义EC策略,该文件必须包含以下三个部分:
layoutversion: 这表示EC策略XML文件格式的版本。
schemas: 包含所有用户自定义的EC模式。
policies: 包含所有用户自定义的EC策略,每个策略由模式ID和条带单元大小(cellsize)组成。
Hadoop配置目录中提供了一个名为user_ec_policies.xml.template的EC策略XML示例文件,可供用户参考。
Intel ISA-L Intel ISA-L代表英特尔智能存储加速库。ISA-L是一个开源的优化低级函数集合,专为存储应用设计。它包含针对英特尔AVX和AVX2指令集优化的快速块里德-所罗门类型擦除码。HDFS擦除编码可以利用ISA-L来加速编解码计算。ISA-L支持大多数主流操作系统,包括Linux和Windows。默认情况下ISA-L未启用。请参阅以下说明了解如何启用ISA-L。
Erasure coding在CPU和网络方面对集群提出了额外要求。
编码和解码工作会消耗HDFS客户端和数据节点上额外的CPU资源。
纠删码要求集群中配置的EC条带宽度至少需要对应数量的DataNodes。对于EC策略RS(6,3)来说,这意味着至少需要9个DataNodes。
纠删码文件也会跨机架分布以实现机架容错。这意味着在读写条带化文件时,大多数操作都是跨机架进行的。因此网络二分带宽至关重要。
为了实现机架容错,拥有足够数量的机架非常重要,这样平均每个机架存储的块数不超过EC校验块的数量。计算公式为(数据块数 + 校验块数)/ 校验块数,向上取整。对于EC策略RS(6,3),这意味着至少需要3个机架(通过(6 + 3)/3 = 3计算得出),理想情况下需要9个或更多机架以应对计划内和计划外停机。对于机架数量少于校验单元数量的集群,HDFS无法保持机架级容错,但仍会尝试将条带化文件分散到多个节点以保持节点级容错。因此,建议设置具有相似数量DataNode的机架。
默认情况下,所有内置的擦除编码策略都被禁用,除了在dfs.namenode.ec.system.default.policy
中定义的策略默认启用。集群管理员可以根据集群规模和所需的容错特性,通过hdfs ec [-enablePolicy -policy
命令启用一组策略。例如,对于一个有9个机架的集群,像RS-10-4-1024k
这样的策略将无法保持机架级容错,而RS-6-3-1024k
或RS-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的编解码器实现可通过以下客户端和数据节点配置键进行配置: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编解码器,还有一个利用Intel ISA-L库提高编解码器性能的原生实现。对于XOR编解码器,同样支持利用Intel ISA-L库提高性能的原生实现。详情请参阅"启用Intel ISA-L"章节。RS Legacy的默认实现是纯Java,而默认RS和XOR的默认实现是使用Intel ISA-L库的原生实现。
DataNodes上的擦除编码后台恢复工作也可以通过以下配置参数进行调整:
dfs.datanode.ec.reconstruction.stripedread.timeout.millis
- 条带化读取的超时时间。默认值为5000毫秒。dfs.datanode.ec.reconstruction.stripedread.buffer.size
- 读取器服务的缓冲区大小。默认值为64KB。dfs.datanode.ec.reconstruction.threads
- DataNode用于后台重建工作的线程数。默认值为8个线程。dfs.datanode.ec.reconstruction.xmits.weight
- EC后台恢复任务与副本块恢复相比所使用的传输相对权重。默认值为0.5。设置为0
可禁用EC恢复任务的权重计算,即EC任务始终具有1
次传输。擦除编码恢复任务的传输次数计算为读取流数量和写入流数量之间的最大值。例如,如果一个EC恢复任务需要从6个节点读取并向2个节点写入,则其传输次数为max(6, 2) * 0.5 = 3
。副本文件的恢复任务始终计为1
次传输。NameNode利用dfs.namenode.replication.max-streams
减去DataNode上来自副本文件和EC文件传输的xmitsInProgress
总和,来调度该DataNode的恢复任务。HDFS默认RS编解码器的原生实现利用Intel ISA-L库来提升编码和解码计算性能。要启用并使用Intel ISA-L,需要完成三个步骤。
-Dbundle.isal
将isal.lib
目录内容复制到最终的tar文件中。使用该tar文件部署Hadoop。确保HDFS客户端和数据节点上已安装ISA-L。要验证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
: HDFS中的一个目录。这是必选参数。设置策略仅影响新创建的文件,不会影响现有文件。
policyName
: 用于该目录下文件的擦除编码策略。如果配置了'dfs.namenode.ec.system.default.policy',则可以省略此参数。路径的EC策略将设置为配置中的默认值。
-replicate
在目录上应用默认的REPLICATION
方案,强制目录采用3倍复制方案。
-replicate
和-policy
是可选参数。它们不能同时指定。
[-getPolicy -path
获取指定路径下文件或目录的擦除编码策略详细信息。
[-unsetPolicy -path
取消之前通过setPolicy
调用在目录上设置的擦除编码策略。如果目录从其祖先目录继承了擦除编码策略,则unsetPolicy
不会执行任何操作。对未设置显式策略的目录取消策略不会返回错误。
[-listPolicies]
列出HDFS中注册的所有(启用、禁用和已删除)擦除编码策略。只有启用的策略适合与setPolicy
命令一起使用。
[-addPolicies -policyFile
添加用户自定义的擦除编码策略列表。请参考etc/hadoop/user_ec_policies.xml.template文件中的示例策略文件。最大单元大小由属性'dfs.namenode.ec.policies.max.cellsize'定义,默认值为4MB。目前HDFS允许用户总共添加64条策略,添加的策略ID范围在64到127之间。如果已添加64条策略,则添加策略将失败。
[-listCodecs]
获取系统中支持的擦除编码编解码器及其编码器列表。编码器是编解码器的具体实现。一个编解码器可能有不同的实现方式,因此会有不同的编码器。针对某个编解码器的编码器会按回退顺序列出。
[-removePolicy -policy
移除用户自定义的擦除编码策略。
[-enablePolicy -policy
启用一个擦除编码策略。
[-disablePolicy -policy
禁用某个擦除编码策略。
[-verifyClusterSetup -policy
验证集群设置是否支持所有启用的擦除编码策略。如果指定了可选参数-policy,则验证集群设置是否支持给定的一个或多个策略。
由于存在重大技术挑战,某些HDFS操作(如hflush
、hsync
、concat
、setReplication
、truncate
和append
)在纠删码文件上不受支持。
append()
和 truncate()
操作在纠删码文件上会抛出 IOException
。不过,当启用 NEW_BLOCK
标志时,支持对已关闭的条带化文件进行追加操作。concat()
如果文件混合使用了不同的擦除编码策略或包含复制文件,将会抛出 IOException
。setReplication()
对纠删码文件无效。hflush()
和 hsync()
在 DFSStripedOutputStream
上是空操作。因此对纠删码文件调用 hflush()
或 hsync()
不能保证数据持久化。客户端可以使用StreamCapabilities
API来查询OutputStream
是否支持hflush()
和hsync()
。如果客户端希望通过hflush()
和hsync()
实现数据持久化,当前的解决方案是在非纠删码目录中创建常规3副本文件,或者使用FSDataOutputStreamBuilder#replicate()
API在纠删码目录中创建3副本文件。