HDFS 纠删码

在HDFS中,可靠性通过多副本的方式来实现,从而较低的存储利用率成为时下基于HDFS应用的主要问题之一。本文将详细介绍HDFS一个新的特性——Erasure Coding(EC), 它在保证同等(或者更高)可靠性的情况下将存储利用率提高了近一倍。

背景

近些年,随着大数据技术的发展,HDFS作为Hadoop的核心模块之一得到了广泛的应用。然而,随着需要存储的数据被越来越快的产生,越来越高的HDFS存储利用率要求被提出。而对于一个分布式文件系统来说,可靠性必不可少。因此,在HDFS中每一份数据都有两个副本,这也使得存储利用率仅为1/3,每TB数据都需要占用3TB的存储空间。因此,在保证可靠性的前提下如何提高存储利用率已成为当前HDFS应用的主要问题之一。

纠删码技术起源于通信传输领域,后被逐渐运用到存储系统中。它对数据进行分块,然后计算出一些冗余的校验块。当一部分数据块丢失时,可以通过剩余的数据块和校验块计算出丢失的数据块。Facebook 的开源项目HDFS-RAID在HDFS之上使用了纠删码技术。HDFS-RAID对属于同一文件的块分组并依次生成校验块,将这些校验块构成独立的文件,并与原始的数据文件一一对应。RaidNode作为一个新的角色被引入进来,它负责从DataNode中读取文件的数据块,计算出校验块, 并写入校验文件中;同时,它还周期性地检查被编码了的文件是否存在块丢失,如有丢失则重新进行计算以恢复丢失的块。HDFS-RAID的优点是其构建于HDFS之上,不需要修改HDFS本已经复杂的内部逻辑,但缺点也显而易见:校验文件对用户是可见的,存在被误删除的可能;依赖于MySQL和MapReduce来存储元数据和生成校验文件;RaidNode需要周期性地查找丢失的块,加重了NameNode的负担;使用的编解码器性能较差,在实际应用中往往不能满足要求。另外,由于缺乏维护,HDFS已将HDFS-RAID的代码从contrib包中移除,这给使用HDFS-RAID带来不少困难。

2014下半年,英特尔和Cloudera共同提出了将纠删码融入到HDFS内部的想法和设计(HDFS EC),随后吸引了包括Hortonworks、华为、Yahoo!等众多公司的参与,使之成为Hadoop开源社区较为活跃的一个项目。将纠删码融入到HDFS内部带来了诸多好处:它不再需要任何的外部依赖,用户使用起来更为方便;其代码成为HDFS的一部分,便于维护;可以充分利用HDFS的内部机制使性能得到最大程度的优化。纠删码的编解码性能对其在HDFS中的应用起着至关重要的作用,如果不利用硬件方面的优化就很难得到理想的性能。英特尔的智能存储加速库(ISA-L)提供了对纠删码编解码的优化,极大的提升了其性能,这一点将在实验部分做详细的阐述。HDFS EC项目主要要实现以下的功能:

  1. 用户可以读和写一个条形布局(Striping Layout,定义见下文)的文件;如果该文件的一个块丢失,后台能够检查出并恢复;如果在读的过程中发现数据丢失,能够立即解码出丢失的数据从而不影响读操作。
  2. 支持将一个多备份模式(HDFS原有模式)的文件转换成连续布局(Contiguous Layout,定义见下文),以及从连续布局转换成多备份模式。
  3. 编解码器将作为插件,用户可指定文件所使用的编解码器。
    由于HDFS的内部逻辑已经相当复杂,HDFS EC项目将分阶段进行:第一阶段(HDFS-7285)已经实现第1个功能,第二阶段(HDFS-8030)正在进行中,将实现第2和第3个功能。本文将主要阐述第一阶段(HDFS-7285)的设计与实现。

相关概念

纠删码(Erasure Code)与 Reed Solomon码

在存储系统中,纠删码技术主要是通过利用纠删码算法将原始的数据进行编码得到校验,并将数据和校验一并存储起来,以达到容错的目的。其基本思想是将k块原始的数据元素通过一定的编码计算,得到m块校验元素。对于这k+m块元素,当其中任意的m块元素出错(包括数据和校验出错),均可以通过对应的重构算法恢复出原来的k块数据。生成校验的过程被成为编码(encoding),恢复丢失数据块的过程被称为解码(decoding)。

Reed-Solomon(RS)码是存储系统较为常用的一种纠删码,它有两个参数k和m,记为RS(k,m)。如图1所示,k个数据块组成一个向量被乘上一个生成矩阵(Generator Matrix)GT从而得到一个码字(codeword)向量,该向量由k个数据块和m个校验块构成。如果一个数据块丢失,可以用(GT)-1乘以码字向量来恢复出丢失的数据块。RS(k,m)最多可容忍m个块(包括数据块和校验块)丢失。

图片描述

图1 RS(4,2)编码过程示意图

块组(BlockGroup)

对HDFS的一个普通文件来说,构成它的基本单位是块。对于EC模式下的文件,构成它的基本单位为块组。块组由一定数目的数据块加上生成的校验块放一起构成。以RS(6,3)为例,每一个块组包含1-6个数据块,以及3个校验块。进行EC编码的前提是每个块的长度一致。如果不一致,则应填充0。图2给出三种不同类型的块组及其编码。

图片描述

图2 三种类型块组及其编码

连续布局(Contiguous Layout) VS 条形布局(Striping Layout)
数据被依次写入一个块中,一个块写满之后再写入下一个块,数据的这种分布方式被称为连续布局。在一些分布式文件系统如QFS和Ceph中,广泛使用另外一种布局:条形布局。条(stripe)是由若干个相同大小单元(cell)构成的序列。在条形布局下,数据被依次写入条的各个单元中,当条被写满之后就写入下一个条,一个条的不同单元位于不同的数据块中。

图片描述

图3 连续布局与条形布局示意图

总体设计

布局的选择

对HDFS EC来说,首要的问题是选择什么样的布局方式。连续布局实现起来较为容易,但它只适合较大的文件。另外,如果让client端直接写一个连续布局文件需要缓存下足够的数据块,然后生成校验块并写入,以RS(6,3),blockSize=128M为例,client端需要缓存1.12G的数据,这点决定了连续布局的文件更适合由普通文件转化而来,而条形布局就不存在上述缺点。由于一个条的单元往往较小(通常为64K或1M),因此无论文件大小,条形布局都可以为文件节省出空间。client端在写完一个条的数据单元后就可以计算出校验单元并写出,因此client端需要缓存的数据很少。 条形布局的一个缺点是会影响一些位置敏感任务的性能,因为原先在一个节点上的一个块被分散到了多个不同的节点上。
HDFS最初就是为较大文件设计的分布式文件系统,但随着越来越多的应用将数据存储于HDFS上,HDFS的小(即小于1个块组)文件数目越来越多,而且它们所占空间的比率也越来越高。以Cloudera一些较大客户的集群为例,小文件占整个空间的比例在36-97%之间。

基于以上分析,HDFS EC优先考虑对条形布局的支持。下面的设计与实现也主要围绕已经实现了的条形布局展开。

NameNode端扩展

在EC模式下,构成文件的基本单位为块组,因此首先需要考虑的是如何在NameNode里保存每个文件的块组信息。一种比较直接的方法是给每个块组分配一个块ID,同时用一个Map来记录这个ID与块组信息的映射,每个块组信息包含了每个内部块的信息。对小文件来说,这种做法将增加其在NameNode中的内存消耗。以RS(6,3)为例,如果一个文件比6个块略小些,那么NameNode必须为它维护10个ID(1个块组ID、6个数据块ID和3个校验块ID)。在小文件数目占优的情况下,NameNode的内存使用将面临考验。

一个块ID有64位,这里将第1个位作为flag来区分块的类型:如果为1,则为EC块(条形布局的EC块,连续布局将在第二阶段考虑);如果为0,则为普通块。对EC块来说,会将剩下的63位分成两部分:最后的4位用来标识内部块在块组中的位置,前面的59位用来区分不同的块组。块组ID等同于第0个内部块ID,其他的内部块ID可由块组ID加上其在块组中的位置索引得到,比如第0个内部块ID为0xB23400(也即块组ID),那么第3个内部块的ID为0xB23403。由于只是用最后4位来区分一个块组中的内部块,因此对一个块组来说,系统目前支持最多16个内部块。

这样一来就可以尽可能地利用HDFS当前的机制来实现对块组的支持。块组依旧用类Block来表示,其中的三个成员:blockId代表块组ID;numBytes代表块组大小,即所有数据块大小之和,不包括校验块的大小;generationStamp代表块组的生成时间戳,所有内部块共享块组的时间戳。这里可以根据块组的Block对象得到内部块的Block对象:blockId由块组ID加上该内部块在块组中的位置索引;numBytes可由块组大小和该内部块位置索引计算出来;生成时间戳等同于块组的时间戳。每个内部块所在的DataNode信息会存储在其所属块组在BlocksMap中对应的BlockInfo对象中。当一个块被DataNode报告给NameNode时,NameNode可以通过其块ID判断该块的类型,如果为EC块则将最后4位清零便得到块组ID。通过这种方式,我们只存储了一个块组ID,大量内部块的ID通过计算得到。内部块的大小和时间戳也可由块组信息得到,因此大大减少了NameNode内存的占用。

图片描述

图4 NameNode端扩展

当client写满一个块组或刚开始写数据时,它向NameNode申请一个新的块组。新的块组保存于INodeFile中并返回给client。新块组包含各个内部块的DataNode信息,它们由BlockPlacementPolicy确定。这里需要各个内部块尽可能的分布在不同的DataNode或机架上,以免造成多个内部块同时丢失而加大数据丢失的风险。因此,HDFS EC需要使用符合自己要求的BlockPlacementPolicy。

NameNode中有一个守护线程ReplicationMonitor,它会周期性地执行数据块的备份和删除任务,这些任务由类UnderRepliationBlocks和InvalidateBlocks来维护。这种方式也非常适合EC任务,包括丢失块的恢复,块在多备份模式和EC模式之间的转换等。
UnderReplicatedBlocks类负责对副本数不足的块进行复制。它包含多个优先级队列,用于区分不同复制任务的紧急程度。我们可以将一个块组的副本数定义为其数据块和校验块数目之和,如果其中的一个内部块丢失,就将其副本数减1,这样其副本数就不足,就可以放入到UnderReplicatedBlocks的某一个队列中。可以根据丢失的内部块的数目来决定加入到哪个优先级队列中。当选定的DataNode传来心跳时,NameNode向该DataNode发送一个BlockECRecoveryCommand,DataNode接收到该命令将启动一个恢复任务。需要注意的是,当发现一个块组缺损后未必立即启动恢复任务,因为恢复任务会消耗大量的网络带宽,以RS(6,3)为例,承担任务的DataNode需要读取6个内部块用于解码工作。如果一个集群每天有1%-2%的节点宕掉的话,立即启动恢复任务可能会耗尽系统的带宽。因此,恢复任务的执行需要配合一定的策略,例如,优先执行缺损厉害的块组,每天限定恢复任务的数量,在系统空闲时启动恢复任务等。

Client 端扩展

用户在写一个文件前可以先指定该文件为EC模式,也可以对一个文件夹指定EC模式,然后所有写入该文件夹的文件都默认为EC模式。

client写

HDFS client通过输出流DFSOutputStream向文件系统写入数据。DFSOutputStream的实现较为复杂,为了能够对其进行功能扩展,我们对该类进行重构,将内部类DataStreamer和Packet(重命名为DFSPacket)独立出来,使得各个类都有清晰独立的功能,从而为实现EC模式下的写操作提供便利。

当写一个条形布局的文件时,需要将数据分散地写到多个DataNode上,为此,我们实现了DFSOutputStream的子类DFSStripedOutputStream,它拥有多个并发的DataStreamer。图5给出了DFSStripedOutputStream的内部工作原理。

图片描述

图 5 DFSStripedOutputStream工作原理

数据以条形布局的方式写入到CellBuffers中。CellBuffers拥有多个缓存,每个缓存对应条中的一个单元,也对应着一个DataStreamer。当一个条中的数据单元写完之后,DFSStripedOutputStream会立刻计算出校验单元并写入到校验块缓存中。当一个缓存中的数据能够装满一个DFSPacket时,该缓存就将数据装入一个DFSPacket并传给该缓存对应的DataStreamer。当数据写完准备关闭文件时,最后的一个条可能数据单元没有写满,这时需要对数据单元补零后生成该条的校验单元并写入校验块缓存中, 然后生成最后的DFSPacket并将它们发送至各自的DataStreamer。

在写一个新的块组前,DFSStripedOutputStream会向NameNode申请分配一个新块组。NameNode会返回一个LocatedBlock对象,该对象包含每个内部块的DataNode信息。DFSStripedOutputStream会解析该对象,生成出各个内部块然后发送给Coordinator。Coordinator负责各个DataStreamer与DFSStripedOutputStream的协调工作:DataStreamer会等待Coordinator传递给它一个内部块用于创建数据流通道;当DataStreamer开始工作后,DFSStripedOutputStream便会在Coordinator上等待各个DataStreamer的工作结果;DataStreamer写完一个内部块后会向Coordinator发送一个结束块,以汇报此次工作的结果(如写入多少字节的数据);Coordinator搜集到所有的结束块后汇报给等待在其上的DFSStripedOutputStream;DFSStripedOutputStream据此来决定后续步骤,如果太多的DataStreamer失败,则结束写操作并返回,否则转向处理CellBuffers中新的数据。

DFSStripedOutputStream在写过程中可以容忍一定数目的DataStreamer失败。以RS(6,3)为例,如果在写一个块组时,失败的DataStreamer不超过3个,那么失败的内部块在以后读取时被计算。 当下一个块组到来,失败的DataStreamer又可以重新开始写一个新的块。

client端读

client读一个条形布局文件的逻辑要相对简单。由于数据源分布在多个DataNode上,因此在进行读的时候需要连接多台数据块所在的DataNode。 读操作的扩展功能由DFSStripedInputStream实现,它继承了DFSInputStream。

DFSStripedInputStream以条为单位进行读取。

client在写的时候,如果一个块组中只有较少的内部块写操作失败,client会继续写下去。因此,client在读的时候就会遇到个别数据块丢失的情况。为了能使读操作进行下去,client需要连接一定数目的校验块,读取相应的校验数据并通过解码来得到丢失的数据。这种情况下,client需要连接更多的DataNode以获取参与解码的校验数据,并且解码也会消耗client一定的CPU资源。为了减少这种情况的发生,我们需要在后台来检测有缺失的块组并进行恢复。

Datanode 端扩展

DataNode端的扩展主要是为了实现后台对丢失数据块的解码,以及对数据块进行编码生成校验块,编码部分将在第二阶段实现。

图片描述

图 6 DataNode端扩展

图6展示了DataNode端的扩展。为了独立的处理EC相关的任务,我们在DataNode中添加了一个新的类ErasureCodingWorker。该类维护了一个线程池,每当有一个解码任务到来时,便会将任务交由ReconstructAndTransferBlock线程处理。ReconstructAndTransferBlock线程从若干个DataNode读取解码所需要的数据,执行解码计算,然后将恢复出来的块保存到目标节点上。一旦任务完成,ErasureCodingWorker会向NameNode发送一个确认。

性能测试

纠删码的编解码是非常消耗CPU的,如果不对其进行优化则很难满足实际应用的要求。英特尔的开源智能存储加速库ISA-L,通过利用硬件的高级指令集(如SSE,AVX,AVX2)来实现了编解码的优化。ISA-L同时支持Linux和Windows平台。

在HDFS EC中,我们实现了两种形式的Reed-Solomon算法:一种是纯Java实现,另一种是基于英特尔的ISA-L。我们将在实验中比较这两种实现的性能,同时参与比较的还有HDFS-RAID中的实现。所有的实验都选择使用RS(6,3),这也是HDFS EC中的默认值。
图7显示了内存中各个编解码器的性能比较。从图中我们可以看出,ISA-L的性能是Java的4-5倍,是HDFS-RAID的20倍左右。

图片描述

图7 不同编解码器性能比较

图片描述

图8 HDFS I/O性能比较

图8给出了不同编解码器HDFS I/O的性能对比。该实验运行于一个11节点的集群上(1个NameNode,9个DataNode,1个client),节点间的网络带宽为10GigE。实验方法为在client节点上向HDFS写和读一个12GB的文件。为了测试解码性能,我们在读之前先杀死两台DataNode。从图8我们可以看出,基于ISA-L的编解码器的性能均远远优于其他编解码器,相对于New Java Coder来说,ISA-L写速度是其6倍,读速度是其3.5倍。条形布局文件的一个块是分布在不同的DataNode上,其读和写都可以并发地进行,从理论上讲,其读写性能应该高于3备份模式。但从实验数据上看,仅ISA-L的性能远远高于3备份模式,其他的编解码器都低于3备份模式,由此我们可以看出,编解码运算有可能成为HDFS读写条形布局文件的瓶颈,而ISA-L对编码器的优化则消除了这个瓶颈。

从上述的实验数据和分析可以看出,如果集群是架构在英特尔平台的服务器上,那么使用了ISA-L的编解码器是最好的选择。

项目进度与计划

HDFS EC第一阶段实现了对条形布局的支持。用户可以读和写一个条形布局的文件,如果发现一个内部块丢失,后台会进行恢复工作。第一阶段代码已经进入trunk,并计划在2.9或3.0版本中发布。第二阶段我们将实现对连续布局的支持。当前我们的编解码器默认使用的Reed-Solomon,将来会添加更多的编解码器如HitchHiker、LRC等。用户也将可以灵活配置文件所对应的编解码器。

总结

将纠删码技术融入到HDFS中,可以保证在同等(或者更高)可靠性的前提下,将存储利用率提高了一倍。同样的集群用户可以存储两倍的数据,这将大大减少用户硬件方面的开销。编解码运算要消耗大量的CPU资源,而基于英特尔ISA-L库的编解码器极大地提高了编解码性能,从而使得编解码的计算不再成为瓶颈。

转自:https://blog.csdn.net/karamos/article/details/80123501?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase

本文主要内容翻译自:
https://hadoop.apache.org/docs/r3.1.1/hadoop-project-dist/hadoop-hdfs/HDFSErasureCoding.html
个人添加了几个命令的示例。

目录

  • 目标
  • 背景
  • 架构
  • 部署
    • 集群和硬件配置
    • 配置项
    • 使用 Intel ISA-L
    • 管理命令
  • 限制

目标

复制成本高昂——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支持条带化(striping)的EC。将来,HDF还将支持连续的EC布局。更多信息见设计文件和 HDFS-7285 的讨论。

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

  • Client Extensions - 由于可以并行地处理块组中的多个内部块,客户端的读写路径得到了增强。在input/read路径上,DFSStripedOutputStream管理一组数据流,每个DataNode在当前块组中存储一个内部块。数据流大多是异步工作的。协调器(coordinator)负责整个块组的操作,包括结束当前块组、分配新块组等。在input/read路径上,DFSStripedInputStream 将数据逻辑字节范围的请求转换为存储在DataNode上的内部块。然后它并行地发起read请求。当失败时,它发起额外的读请求进行解码。

  • DataNode Extensions - Datanode运行一个额外的ErasureCodingWorker(ECWorker)任务,用于后台恢复失败的纠删码块。Namenode检测到失败的EC块,然后选择一个DataNode进行恢复工作。恢复任务以作为心跳响应来传递。此过程与失败时如何re-replicated复制块类似。重建执行三个关键任务:

    1. 从源节点读取数据:使用专用线程池从源节点并行读取输入数据。基于EC策略,它调度对所有源目标的读取请求,并且只读取用于重建的最小输入块数。
    2. 解码数据并生成输出数据:从输入数据解码新的数据和奇偶校验块。所有丢失的数据和奇偶校验块会一起解码。
    3. 将生成的数据块传输到目标节点:一旦解码完成,恢复的数据块就会传输到目标DataNodes上。
  • Erasure coding policies - 为了适应异构工作负载,我们允许HDFS集群中的文件和目录具有不同的副本和纠删码策略。纠删码策略封装了如何对文件进行encode/decode。每个策略由以下信息片定义:

    1. EC Schema:包括一个EC组(如6+3)中的数据和奇偶校验块的数量,以及编解码器算法(如Reed Solomon、XOR)。
    2. String单元的大小。这决定了条带化读写的粒度,包括缓冲区大小和编码工作。

    策略被命名为 codec-num data blocks-num parity blocks-cell size。当前支持6种内建的策略:RS-3-2-1024k, RS-6-3-1024k, RS-10-4-1024k, RS-LEGACY-6-3-1024k, XOR-2-1-1024k 及 REPLICATION.

    复制(REPLICATION)是一种特殊策略。它只能在目录上设置,强制目录采用3x复制方案,而不是继承其祖先的纠删码策略。此策略使3x复制方案目录与纠删码目录交错成为可能。

    复制(REPLICATION)策略始终是启用状态。对于其他内置策略,默认情况下它们是不可用的。

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

    目录级的EC策略只影响在目录中的新建文件。创建文件后,可以查询其擦除编码策略但不能更改。如果将一个已经编码了的文件重名到一个使用了不同EC策略的目录中,则该文件将保留其现有的EC策略。如果要将文件转换为其他EC策略需要重写其数据;应该通过复制文件(例如,通过distcp)而不是重命名文件来完成此操作。

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

    1. 布局版本(layoutversion):表示EC策略XML文件格式的版本。
    2. 模式(schemas):包括所有用户定义的EC模式。
    3. 策略(policies):包括所有用户定义的EC策略,每个策略由模式ID和条带单元的大小(cell size)组成。

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

  • Intel ISA-L Intel ISA-L代表Intel Intelligent Storage Acceleration Library(Intel智能存储加速库)。ISA-L是为存储应用程序设计的优化低级功能的开源集合。它包括为Intel AVX和AVX2指令集优化的快速块Reed-Solomon 方式的纠删码。HDFS纠删码可以利用ISA-L加速编码和解码计算。ISA-L支持大多数主流操作系统,包括Linux和Windows。默认情况下不启用ISA-L。有关如何启用ISA-L,请参阅下面的说明。

部署

集群和硬件配置

纠删码会在CPU和网络方面对集群提出额外的要求。

编码和解码工作在HDFS Client和DataNode上都会消耗额外的CPU。

纠删码要求集群中的数据节点最少与配置的EC条带宽度相同。对于EC策略RS(6,3),这意味着至少要有9个数据节点。

为了实现机架容错,纠删码化的文件也分布在机架上。这意味着在读取和写入条带化的文件时,大多数操作都是off-rack(脱离机架)的。因此,网络二分(Network bisection)带宽非常重要。

为了实现机架容错,至少具有与配置的EC条带宽度相同的机架数也是很重要的。对于EC策略RS(6,3),这意味着至少需要9个机架,最好是10或11个机架,以处理计划内和计划外停机。对于机架少于条带宽度的集群,HDFS无法保持机架容错,但仍将尝试在多个节点上分布条带文件,以保持节点级容错。

配置项

默认,所有的内建EC策略都是不可用的,除了由配置项 dfs.namenode.ec.system.default.policy 指定的策略默认是可用的。集群管理员可以基于集群规模和期望的容错性使用命令 hdfs ec [-enablePolicy -policy ] 设置可用的策略,比如,对于一个有9个rack的集群,如果设置的策略是 RS-10-4-1024k 就不会保留rack级的容错了,更适合的策略是RS-3-2-1024k 和 RS-6-3-1024k。如果管理员只在乎node级的容错,那么只要集群有14个以上的DataNode,RS-10-4-1024k策略也是合适的。

系统默认的可用策略,可以通过配置项 dfs.namenode.ec.system.default.policy 指定。使用此配置,当没有策略名作为“-setpolicy”命令中的参数传递时,将使用默认EC策略。

默认 dfs.namenode.ec.system.default.policy 的值是 RS-6-3-1024k

Reed Solomon和XOR的编解码器实现可以使用以下客户端和DataNode的配置项进行配置:默认的RS编解码器是 io.erasureCode.codec.rs.rawcoders,legacy RS编解码器是io.erasureCode.codec.rs-legacy.rawcoders,XOR的编解码器是io.erasureCode.codec.xor.rawcoders。用户也可以使用配置项自定义编解码器: io.erasurecode.codec.self-defined-codec.rawcoders,这些配置项的值都是有回退机制的编解码器名称列表。这些编解码器工厂按配置值指定的顺序加载,直到成功加载一个编解码器。默认的RS和XOR编解码器配置更喜欢纯Java的Native实现。没有RS-LEAGCY的Native编解码器实现,因此默认仅为纯Java实现。所有这些编解码器都使用纯Java实现。对于默认的RS编解码器,还有一个native实现,它利用Intel ISA-L库来提高编解码器的性能。对于XOR编解码器,也有一个native实现利用Intel ISA-L库提高编解码器性能。可以参阅“启用Intel ISA-L”一节了解更多信息。RS Legacy的默认实现是纯Java,默认的RS和XOR的默认实现是使用英特尔ISAL-L库的native实现。

DataNode上的纠删码后台恢复工作也可以通过以下的配置参数进行调整:

  1. dfs.datanode.ec.restruction.stripedread.timeout.millis - 条带读取超时时间。默认为5000 ms。
  2. dfs.datanode.ec.restruction.stripedread.buffer.size - 读服务的缓冲区大小。默认为64KB。
  3. dfs.datanode.ec.restruction.threads - DataNode用于后台重建工作的线程数。默认为8个线程。
  4. dfs.datanode.ec.restruction.xmits.weight - EC后台恢复任务与复制的块恢复相比使用的xmits的相对权重,默认值为0.5。设置为0表示禁用计算EC恢复任务的权重,也就是说,EC任务总是有1个xmit。纠删码码恢复任务的xmit取读取流数量和写入流数量之间的最大值。例如,如果一个EC恢复任务需要从6个节点读取并写入2个节点,那么它的xmits为max(6,2)*0.5=3。复制文件的恢复任务始终计为1 xmit。namenode使用 df.namenode.replication.max-streams 减去datanode上的 xmitsinprogress 总数,后者将replicated文件和ec文件中的xmits组合在一起,以将恢复任务调度到此 datanode。

使用Intel ISA-L

HDFS默认的RS编解码器的native实现利用了 Intel ISA-L库提升编码和解码计算性能。使用 Intel ISA-L 有三个步骤:

  1. 构建 ISA-L库。详细信息,参阅官方网站 https://github.com/01org/isa-l/
  2. 构建hadoop对 ISA-L的支持,请参阅源代码(building.txt)中“Build instructions for Hadoop”中的“Intel ISA-L build options”部分。
  3. 使用 -Dbundle.isal 将isal.lib目录的内容复制到最终的tar文件中。使用tar文件部署hadoop。确保ISA-L在HDFS客户机和DataNode上可用。

使用hadoop checknative命令验证hadoop是否正确检测到ISA-L。

管理命令

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>]
     [-help [cmd ...]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

下面是关于命令的详细说明:

  • [-setPolicy -path [-policy ] [-replicate]]
    设置纠删码策略到指定路径的目录上,
    path: HDFS中的一个目录,这是一个必选参数,设置的策略只会影响到新建的文件,对于已经存在的文件不会有影响。
    policyName: 指定纠删码策略的名称,如果配置项 dfs.namenode.ec.system.default.policy设置了,这个参数可以省略。路径的EC策略就会使用配置项中的默认值
    -replicate 适用于特殊的REPLICATION策略,强制目录采用 3x 复制schema
    -replicate-policy 是可选参数,二者不能同时使用

    示例:

    $ hdfs ec -setPolicy -path /tmp/ecdata
      Set RS-6-3-1024k erasure coding policy on /tmp/ecdata
    
    • 1
    • 2
  • [-getPolicy -path ]
    获取指定路径的目录或文件的纠删码的详细信息

    示例:

    $ hdfs ec -getPolicy -path /tmp/ecdata
    RS-6-3-1024k
  • 1
  • 2
  • [-unsetPolicy -path ]
    取消指定目录之前设置的纠删码策略,如果目录从祖先目录继承了纠删码策略,则unsetpolicy为no-op,也就是如果我们对一个目录执行了取消策略的操作,如果它的祖先目录设置过了策略,那么取消操作是不会生效的。在没有显式策略集的目录上取消策略不会返回错误。

    示例:

	$ hadoop fs -mkdir /tmp/ecdata/data1
	$ hdfs ec -getPolicy -path /tmp/ecdata/data1
	RS-6-3-1024k
	$ hdfs ec -unsetPolicy -path /tmp/ecdata/data1
	Unset erasure coding policy from /tmp/ecdata/data1
	$ hdfs ec -getPolicy -path /tmp/ecdata/data1
	RS-6-3-1024k
	$ hadoop fs -put test.zip  /tmp/ecdata/data1/123
	$ hadoop fs -du -s -h /tmp/ecdata/data1
	112.0 M  169.0 M  /tmp/ecdata/data1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • [-listPolicies]
    列出所有注册到HDFS(enabled, disabled 和 removed)的EC策略,只有状态为enabled的策略才能使用setPolicy命令设置

    示例:

$ hdfs ec -listPolicies
Erasure Coding Policies:
ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=DISABLED
ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=DISABLED
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • [-addPolicies -policyFile ]
    添加EC策略,可以参考etc/hadoop/user_ec_policies.xml.template文件查看示例策略文件,最大的cell大小有选项 dfs.namenode.ec.policies.max.cellsize 定义,默认是4MB。当前HDFS支持添加最多64种策略,策略ID的范围是 64-127,如果已经添加了64中策略,那么后面的添加会失败。

  • [-listCodecs]
    获取系统中支持的EC codecs 和coders 的列表。coder是codec的实现。codec可以有不同的实现,也就是不同的coder。一个codec的coder按返回顺序列出。

    示例:

	$ hdfs ec -listCodecs
	Erasure Coding Codecs: Codec [Coder List]
	        RS [RS_NATIVE, RS_JAVA]
	        RS-LEGACY [RS-LEGACY_JAVA]
	        XOR [XOR_NATIVE, XOR_JAVA]
  • 1
  • 2
  • 3
  • 4
  • 5
  • [-removePolicy -policy ]
    删除EC策略

  • [-enablePolicy -policy ]
    启用EC策略

    示例:

	$ hdfs ec -enablePolicy -policy XOR-2-1-1024k
	$ hdfs ec -listPolicies
	Erasure Coding Policies:
	ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
	ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=DISABLED
	ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
	ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
	ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=ENABLED
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • [-disablePolicy -policy ]
    禁用EC策略

    示例:

	$ hdfs ec -disablePolicy -policy XOR-2-1-1024k
	Erasure coding policy XOR-2-1-1024k is disabled
	$ hdfs ec -listPolicies
	Erasure Coding Policies:
	ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
	ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=DISABLED
	ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
	ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
	ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=DISABLED
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

限制

由于一些重大技术挑战,某些HDFS操作,即hflush, hsync, concat, setReplication, truncate 和 append ,目前并不支持EC文件。

  • append() 和 truncate() 在EC文件上会抛出IOException
  • concat() 会抛出IOException 如果文件中混合着不同的EC策略或者replicated文件。
  • setReplication() 在EC文件上是no-op(不生效)的
  • hflush() 和 hsync()在 DFSStripedOutputStream 是 no-op 的。因此调用hflush() 或者 hsync() 在一个EC化的文件上不能保证数据会被持久化。

客户端可以使用StreamCapabilities API来查询一个OutputStream是否支持hflush() 和 hsync(),如果客户端期望通常 hflush() 和 hsync() 实现数据持久化,当前最好的办法就是在一个non-erasure-coded 目录中创建常规 3x 副本文件,或者使用 FSDataOutputStreamBuilder#replicate() API在erasure-coded 目录中创建3x 副本文件。

转自:https://blog.csdn.net/CPP_MAYIBO/article/details/89978275?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase

猜你喜欢

转载自blog.csdn.net/sinat_22510827/article/details/108292408