更新时间:2022-12-08 GMT+08:00

配置HDFS EC存储

操作场景

为了保证数据的可靠性,HDFS的默认数据存储策略是3副本,即在写入数据的时候,会占用该数据大小3倍的空间。这样就造成了大量的空间浪费。对此,HDFS引入在RAID磁盘阵列中已应用成熟的技术:EC(Erasure Coding,纠删码)。

EC的原理就是,通过将1个文件打散成很小的数据块(如128k、256k、1M等),然后将这些数据块打散存储于多个DN中,然后在另外的若干个DN中存储EC编解码算法生成的校验块。如果某个存储文件块的DN不可用后,将可以通过其他DN中存储的数据块和校验块反向计算出来这个丢失的数据块。

不同的EC编解码算法、数据块大小、数据块和校验块个数,可以构成不同的EC策略。下面以RS-6-3-1024k这种策略说明下EC策略的定义:
  1. 使用RS(Reed Solomon)编解码算法。
  2. 6个DN用于存储数据块。
  3. 3个DN存储校验块。
  4. 最大可以容忍3个块丢失的异常情况。
  5. 每个文件块的大小为1024k(即1MB)。
  6. 如果使用该EC策略存储的文件为100MB,则写入DataNode中的总数据量为(1+3/6) * 100MB=150MB。其中:
    1. 数据块总大小为文件大小100MB。
    2. 校验块总大小为3/6 * 100MB=50MB。

普通的3副本存储和EC存储的区别示意如下:

图1 普通的副本存储
图2 EC存储

使用EC存储后,可以在提供相同可靠性的前提下,节省大量的存储空间。例如,要达到3副本相同的可靠性,仅需要1.5倍的原文件大小即可,从而节约一半的存储空间(原先需要3倍的原文件大小)。

  • HDFS内置的EC编解码算法有:XOR(异或)、RS-LEGACY(旧版Reed-Solomon,性能较差,不建议使用)、RS(新版Reed-Solomon,性能是RS-LEGACY的5倍)。
  • HDFS内置的EC策略有:RS-3-2-1024k,RS-6-3-1024k,RS-10-4-1024k,RS-LEGACY-6-3-1024k,XOR-2-1-1024k。
  • HDFS支持通过客户端命令添加自定义EC策略。
  • 仅支持对目录设置EC策略,不能对文件设置EC策略。
  • 给某个目录设置EC策略后,该目录下的所有未设置EC策略的目录都会继承该目录的EC策略。
HDFS引入了EC特性后,在减少磁盘使用量时,当然也引入了一些问题与限制:
  • 文件在存储时被打散到多个DN中,文件读取不再有“本地读”的概念,导致了数据失去亲和性,引发了非常严重的数据倾斜。
  • 写入文件时,都需要计算(生成校验块、或通过校验块校验),这会消耗更多CPU,使复杂度增高。
  • 在DN节点不可用时,需要通过计算得到缺失的数据块,这会消耗更多CPU,使复杂度增高、异常恢复时间更长。
  • 客户端在读写文件时,需要同时连接所有涉及的DN读写数据块和校验块。
  • 因为实现的原因,目前不支持2个基本的FileSystem接口:append()、truncate(),调用会直接抛异常。不同EC策略的文件的concat(),也会抛错。

针对这些限制和问题,我们可以得出,该特性适用于一次写入大量数据的场景,不适用于以下的场景:

  • 大量小文件
  • 数据量很小的文件
  • 打开后长期持续写入的文件
  • 需要调用append()或truncate()接口修改的文件

对系统的影响

相比副本存储,EC存储对系统有如下影响:

  • NameNode、DataNode、客户端都需要消耗更多的CPU、内存、网络资源。
  • DataNode异常后,需要更长时间来恢复该DataNode上的数据,同时也会降低相关文件的读取性能。

针对这些影响,在准备使用EC的集群上,建议根据业务负载进行如下操作:

  • 调大NameNode、DataNode的“GC_OPTS”中内存参数(主要是-Xmx的值)。
  • 调大HDFS客户端及依赖于HDFS的上层组件的内存参数。
  • 调大DataNode的数据连接线程数参数“dfs.datanode.max.transfer.threads”
  • 当集群中DataNode数量小于20时,建议修改“dfs.namenode.redundancy.considerLoad”“false”

前提条件

  • 已安装好HDFS客户端,并可使用。具体操作请参见使用HDFS客户端
  • 如果是安全模式集群,创建属于supergroup组的用户,并执行kinit user登录Kerberos。
  • 如果是普通模式集群,执行 export HADOOP_USER_NAME=omm

操作命令说明

  • 列出当前集群中所有支持的EC编解码算法:hdfs ec -listCodecs。示例:
    [root@10-219-254-200 ~]#hdfs ec -listCodecs
    Erasure Coding Codecs: Codec [Coder List]
    RS [RS_NATIVE, RS_JAVA]
    RS-LEGACY [RS-LEGACY_JAVA]
    XOR [XOR_NATIVE, XOR_JAVA]
  • 列出当前集群中所有的EC策略:hdfs ec -listPolicies。示例:
    [root@10-219-254-200 ~]#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

  • 启用指定的EC策略:hdfs ec -enablePolicy -policy <policyName>。示例:
    [root@10-219-254-200 ~]#hdfs ec -enablePolicy -policy RS-3-2-1024k
    Erasure coding policy RS-3-2-1024k is enabled

    只有启用(ENABLED)状态的EC策略,才能设置给目录。

  • 停用指定的EC策略:hdfs ec -disablePolicy -policy <policyName> 。示例:
    [root@10-219-254-200 ~]#hdfs ec -disablePolicy -policy RS-3-2-1024k
    Erasure coding policy RS-3-2-1024k is disabled
  • 新增自定义EC策略:hdfs ec -addPolicies -policyFile <配置文件路径>
    1. 需要先编写自定义EC策略的配置文件(可以参考 <HDFS客户端安装目录>/HDFS/hadoop/etc/hadoop/user_ec_policies.xml.template 样例来编写)。样例内容如下:
      <?xml version="1.0"?>
      <configuration>
      <!-- The version of EC policy XML file format, it must be an integer -->
      <layoutversion>1</layoutversion>
      <schemas>
        <!-- schema id is only used to reference internally in this document -->
        <schema id="XORk2m1">
          <!-- The combination of codec, k, m and options as the schema ID, defines
           a unique schema, for example 'xor-2-1'. schema ID is case insensitive -->
          <!-- codec with this specific name should exist already in this system -->
          <codec>xor</codec>
          <k>2</k>
          <m>1</m>
          <options> </options>
        </schema>
        <schema id="RSk12m4">
          <codec>rs</codec>
          <k>12</k>
          <m>4</m>
          <options> </options>
        </schema>
        <schema id="RS-legacyk12m4">
          <codec>rs-legacy</codec>
          <k>12</k>
          <m>4</m>
          <options> </options>
        </schema>
      </schemas>
      <policies>
        <policy>
          <!-- the combination of schema ID and cellsize(in unit k) defines a unique
           policy, for example 'xor-2-1-256k', case insensitive -->
          <!-- schema is referred by its id -->
          <schema>XORk2m1</schema>
          <!-- cellsize must be an positive integer multiple of 1024(1k) -->
          <!-- maximum cellsize is defined by 'dfs.namenode.ec.policies.max.cellsize' property -->
          <cellsize>131072</cellsize>
        </policy>
        <policy>
          <schema>RS-legacyk12m4</schema>
          <cellsize>262144</cellsize>
        </policy>
      </policies>
      </configuration>
    2. 自定义添加的EC策略,默认是停用(DISABLED)状态的,需要启用后才能使用。

    示例如下:

    [root@10-219-254-200 ~]#hdfs ec -addPolicies -policyFile  /opt/client/HDFS/hadoop/etc/hadoop/user_ec_policies.xml.template
    2018-12-31 17:50:17,666 INFO util.ECPolicyLoader: Loading EC policy file /opt/client/HDFS/hadoop/etc/hadoop/user_ec_policies.xml.template
    Add ErasureCodingPolicy XOR-2-1-128k succeed.
    Add ErasureCodingPolicy RS-LEGACY-12-4-256k succeed.
  • 删除指定的EC策略:hdfs ec -removePolicy -policy <policy>。示例:
    [root@10-219-254-200 ~]#hdfs ec -removePolicy -policy XOR-2-1-128k
    Erasure coding policy XOR-2-1-128k is removed
  • 设置目录的EC策略:hdfs ec -setPolicy -path <path> [-policy <policy>] [-replicate]。示例:
    [root@10-219-254-200 ~]#hdfs ec -setPolicy -path /test -policy RS-6-3-1024k
    Set RS-6-3-1024k erasure coding policy on /test
    Warning: setting erasure coding policy on a non-empty directory will not automatically convert existing files to RS-6-3-1024k erasure coding policy
    • 给一个目录设置EC策略后,该目录下已有文件将不受影响(存储方式不变),而新创建的文件将按照设置的EC策略来存储。
    • -replicate参数,用来给目录设置3副本存储策略,而非EC策略。
    • -replicate 和 -policy <policyName>不能同时使用。
  • 获取指定目录的EC策略:hdfs ec -getPolicy -path <path>。示例:
    [root@10-219-254-200 ~]#hdfs ec -getPolicy -path /test
    RS-6-3-1024k
  • 取消指定目录的EC策略:hdfs ec -unsetPolicy -path <path>。示例:
    [root@10-219-254-200 ~]#hdfs ec -unsetPolicy -path /test
    Unset erasure coding policy from /test
    Warning: unsetting erasure coding policy on a non-empty directory will not automatically convert existing files to replicated data.

    当一个目录被取消EC策略后,如果其父目录有EC策略,则将继承其父目录的EC策略。

上层服务使用EC的建议

根据EC存储的现状,推荐使用EC的上层服务有:Yarn、Mapreduce、HBase、Hive、Spark2x。

各服务具体适用EC存储的HDFS目录如表1所示:

表1 EC存储目录

上层服务

HDFS目录

配置项

存储数据用途

Yarn

/tmp/logs

yarn.nodemanager.remote-app-log-dir

存放container日志文件

/tmp/archived

yarn.nodemanager.remote-app-log-archive-dir

存放归档的任务日志文件

Mapreduce

/mr-history/tmp

-

Mapreduce作业产生的日志存放位置

/mr-history/done

-

MR JobHistory Server管理的日志的存放位置

HBase

/hbase/.tmp

-

建表等临时目录

/hbase/archive

-

归档目录

/hbase/data

-

表数据目录

Hive

/user/hive/warehouse

hive.metastore.warehouse.dir

Hive数据仓库目录

/tmp/hive-scratch

hive.exec.scratchdir

Hive 作业运行的临时数据目录

Spark2x

/user/hive/warehouse

hive.metastore.warehouse.dir

默认存放表数据的目录

上层服务的部分数据目录如表2,不能使用EC策略,否则将导致业务运行失败。如果这些目录设置了EC策略,HDFS将自动取消其EC策略,并设置为副本策略。

表2 数据目录

上层服务

HDFS目录

配置项

存储数据用途

公共

/tmp

-

HDFS的临时目录,存放临时文件

/user

-

HDFS的用户目录,用于存放用户数据

HBase

/hbase

hbase.data.rootdir

HBase数据的根目录

/hbase/.hbase-snapshot

-

表的Snapshot目录

/hbase/.hbck

-

存放hbck检查的不合符的(比如越界)hfile

/hbase/MasterProcWALs

-

存放Proc的log

/hbase/WALs

-

存放Wal

/hbase/corrupt

-

存放损坏的hfile

/hbase/oldWALs

-

WALs中的数据将移动到oldWALs

Spark2x

/user/spark2x

spark.yarn.stagingDir

存放Spark2x应用运行时生成的临时文件

/tmp/spark2x/sparkhive-scratch

hive.exec.scratchdir

JDBCServer执行sql时存放临时文件的目录

/spark2xJobHistory2x

spark.eventLog.dir

存放event log的目录

/user/spark2x/jars

-

存放Spark2x jar包压缩文件的目录

CarbonData

/user/hive/warehouse/carbon.store/

carbon.storelocation

数据文件

Flink

/flink

-

保存flink运行快照信息,用于任务恢复

可以通过HDFS的配置项“dfs.no.ec.dirs”自定义不让使用EC策略的HDFS目录列表,用逗号分隔。

EC与存储策略

EC目录所支持的存储策略有:HOT,COLD,ALL_SSD

如果设置为其他存储策略(如WARM、ONE_SSD、PROVIDED、LAZY_PERSIST),则将使用默认的存储策略,即HOT策略。

由于EC文件的读写,需要获取所有块的信息。为了保证所有块的读写耗时的一致性,所以EC文件的块需要存储在同样性能的磁盘上。满足该条件的存储策略只有这三种:HOT,COLD,ALL_SSD

EC对于Distcp的影响

如果Distcp的源文件有EC文件时,需要针对不同的需求,添加不同的参数:

  • 如果在拷贝过程中,保持文件的EC策略,需要在Distcp时加入参数:-preserveec
  • 如果不需要保持源文件的EC策略,而按照目的目录的EC策略(或副本策略)来将文件重写到目的目录,则需要在Distcp时加入参数:-skipcrccheck

    如果不加这两个参数之一,则不同EC策略的文件,会因为其校验值不同而导致Distcp任务失败。

副本文件和EC文件的相互转换

副本文件转换成EC文件(例如把/src目录下的全部文件转换为“RS-6-3-1024k”策略的EC文件)

  1. 创建一个临时目录(如“/tmp/convert_tmp_dir”,必须是不存在的目录),用于临时存储转换完成的数据。

    hdfs dfs -mkdir /tmp/convert_tmp_dir

  2. 启用EC策略“ RS-6-3-1024k”(如果已启用,可以跳过此步骤)。

    hdfs ec -enablePolicy -policy RS-6-3-1024k

  3. 设置“/tmp/convert_tmp_dir”的EC策略为“RS-6-3-1024k”

    hdfs ec -setPolicy -path /tmp/convert_tmp_dir -policy RS-6-3-1024k

  4. 使用Distcp拷贝文件,此时所有文件会按照“RS-6-3-1024k”策略写入临时目录。

    hadoop distcp -numListstatusThreads 40 -update -delete -skipcrccheck -pbugpaxt /src /tmp/convert_tmp_dir

  5. 移动“/src”“/src-to-delete”

    hdfs dfs -mv /src /src-to-delete

  6. 移动“/tmp/convert_tmp_dir”“/src”

    hdfs dfs -mv /tmp/convert_tmp_dir /src

  7. 删除“/src-to-delete”

    hdfs dfs -rm -r -f /src-to-delete

    删除文件为高危操作,在执行操作前请务必确认对应文件是否不再需要。

EC文件转换成副本文件(例如把/src目录下的所有文件全部文件转换为副本文件)

  1. 创建一个临时目录(如“/tmp/convert_tmp_dir”,必须是不存在的目录),用于临时存储转换完成的数据。

    hdfs dfs -mkdir /tmp/convert_tmp_dir

  2. 设置“/tmp/convert_tmp_dir”为副本策略。

    hdfs ec -setPolicy -path /tmp/convert_tmp_dir -replicate

  3. 使用Distcp拷贝文件,此时所有文件会按照副本策略写入临时目录。

    hadoop distcp -numListstatusThreads 40 -update -delete -skipcrccheck -pbugpaxt /src /tmp/convert_tmp_dir

  4. 移动“/src”“/src-to-delete”

    hdfs dfs -mv /src /src-to-delete

  5. 移动“/tmp/convert_tmp_dir”“/src”

    hdfs dfs -mv /tmp/convert_tmp_dir /src

  6. 删除“/src-to-delete”

    hdfs dfs -rm -r -f /src-to-delete