Java与大数据架构
7年老码农,10W关注者。【Java与大数据架构】全面分享Java编程、Spark、Flink、Kafka、Elasticsearch、数据湖等干货。
8篇原创内容
Official Account
桔妹导读:HDFS中默认的3副本方案在存储空间和其他资源(例如网络带宽)上有200%的开销。对于冷数据,使用纠删码(ErasureCoding,EC)存储代替副本存储是一种非常不错的替代方案。EC存储在保证容错能力不低于副本存储的同时,有着更低的存储空间消耗。HDFS EC在滴滴内部稳定落地已超过半年,为公司节约了大量的存储成本。本文将介绍EC在滴滴内部的实践情况。
▍1. EC算法
EC是一种编码容错技术,最早用于通信行业数据传输中的数据恢复。Hadoop3.0版本将EC加入到HDFS中。这里简要介绍EC中使用广泛的两个算法:XOR Codes与Reed-Solomon Codes。
XOR编码即“异或”编码,其原理是:数据编码时按照位进行异或运算,数据解码(数据恢复)时则通过结果与其他数据位进行异或操作。这里,我们不妨抽象成数学运算用于解释,例如:1 ⊕ 1 = 0 中,运算位中的任何一位丢失,则能通过另外两位计算得出,但是如果丢失两位则无法恢复。对应到HDFS中,实现该算法的EC策略是XOR-2-1-1024k,如果使用XOR编码3个数据块,则最多能容忍一个数据块丢失。该编码常用于HDFS测试。
Reed-Solomon Codes缩写为RS码,使用复杂的线性代数运算来生成多个奇偶校验块,因此可以容忍多个数据块故障。RS码在使用的时候需指定2个参数RS(n, m),n代表的是数据块的数量,m代表的是校验块的数量,校验块由数据块编码产生。RS编码的编码与解码原理如图1所示(网络图)。编码时,利用生成矩阵B(这里选用范德蒙单位矩阵)与数据列向量D的乘积得到信息列向量D+C;重构时,利用现存的信息列向量Survivors与对应的逆矩阵B'-1 乘积得到原数据列向量D,从而达到恢复原数据的目的。
▍2.HDFS EC块布局
先回顾一下3副本存储的连续存储方式(Contiguous Block Layout),3副本存储以块(Block)为单位,会将数据连续写入Block中,直至达到该Block大小(如128M)再去申请下一个Block,每个Block会有3个相同数据的副本存于3个DataNode(DN)上。连续存储示意图如图2(a)所示。HDFS EC采用条带条带式存储布局(Striping Block Layout)。条带式存储是以块组(BlockGroup)为单位,横向式地将数据保存在各个Block上,同一个Block上的不同分段的数据是不连续的。写完一个块组再申请下一个块组。条带式的存储结构图2(b)所示(图示为RS(6,3)策略下1个BlockGroup布局示意图)。
图2(a) 3副本存储示意图
图2(b) EC存储示意图
▍1. EC落地工作
为了将EC存储引入生产环境,我们做了如下的定制和优化。
EC是Hadoop3才有的新特性,因此服务端需要升级。在EC投入生产环境之前,滴滴内部已经完成了HDFS 2.7版本到3.2版本的滚动升级(不停服务,对用户无感知)。版本升级的相关总结见「 」。
客户端(Client)受到Spark,Hive,Flink等很多组件依赖,目前这些组件还不支持Hadoop3,因此客户端暂时保持2.7版本不变,这就要求内部的Hadoop2.7版本客户端要做EC读写兼容。我们将Hadoop3.2中的hadoop-common、hadoop-hdfs、hadoop-hdfs-client 中关于EC读写相关部分移植到Hadoop2.7版本。同时,RBF部分也需要做相应的兼容工作。这里,我们展示一些代码举例,例如,在hdfs.proto协议和ClientNamenodeProtocol.proto协议中,我们增加了EC相关字段:
目前,将文件转为EC存储的途径是将文件写入启用EC特性的目录中(社区正在开发更优雅的方式见:
HDFS-14978)。将文件/目录mv到已启用EC的目录不会自动转换存储方式,只有写操作才会。因此,通常执行以下步骤来将副本存储方式的文件转EC存储方式:
为了能够可靠地、高效地将副本文件转EC,滴滴内部做了如下工作:
定制distcp工具。在将副本文件转EC文件后,必须要保证数据一致性。这就要求复制的源和目标文件checksum必须相同。由于存储方式不同,使用传统的CRC校验方式不能适用于副本文件和EC文件的校准。因此,定制版本将Hadoop3中的COMPOSITE_CRC校验方式(HDFS-13056)引入到Hadoop2的distcp中供内部使用。
自研转EC系统(Anty系统)用于周期性(或手动)执行转EC作业,以及统计集群EC文件存储量、占比等信息。具体介绍见后文的实践场景部分。
内部资产平台需要周期性地离线分析整个集群的存储空间用于评估成本。若对每个文件使用du命令将对NameNode产生不小的压力。解析fsimage镜像文件可以得到每个文件的逻辑大小,副本文件的物理空间计算非常简单,即逻辑大小 * 副本因子;EC文件的物理空间由于其条带式存储而复杂许多,这里简要介绍下计算方法。
考虑到最后一个块组的最后一个strip有两种情况(如图3所示):
第一个块的cell写满了,则校验块cell大小也写满
第一个块的cell只写了k (k<cellSize) 字节,则每个校验块也是k字节
图3 最后一个strip cell写满情况示意图
为了简化计算,可以不用考虑有多少个块组,只关心一共写了多少strip。EC物理存储计算示意图4所示。
由于在Federation集群中会有集群间数据迁移的情况,在3副本文件场景下FastCopy(HDFS-2139)是一个高效的迁移方案,其通过将块进行硬链接的方式来达到快速迁移的目的。由于FastCopy不支持EC文件操作,滴滴内部版本做了FastCopy兼容EC文件的改进,极大地方便了Federation集群间的数据迁移。
首先要考虑的是EC策略的选择。通过hdfs ec -listPolicies命令可以列出已经实现的EC策略。各个策略的一些特性如表1所示。
表1 EC策略特性对比
综合考虑,滴滴内部只开启了RS-6-3-1024k策略。考虑到EC策略目录的规范性,目前只支持管理员设置EC策略。
国内离线集群已有上百P的逻辑数据,数据量的增长对集群的存储也带来了一定压力。为了节约存储成本,滴滴内部对冷数据进行了转EC存储。考虑到并不是所有3副本文件在转EC后都有更少的空间存储,这里需要对转EC的文件做大小限制。在RS(6,3)策略下,我们限制待转EC的目录下的非空平均文件大小>=6M。数据源选择如图5所示。
图5 转EC文件数据源
转EC存储流程如下(自研Anty系统将自动化完成所有过程):
周期性地(每天)从fsimage表中计算出需要转EC的叶子目录
每个目录的转EC、替换原文件操作记为一次pipeline。多个pipeline并行操作进行转EC
每个目录的转EC状态记为该目录的生命周期lifecycle,生命周期有变化时更新到mysql,用于前端页面对转EC情况的展示
整个转EC流程如图6所示。
图6 转EC流程图
经过半年多的实践,生产环境已有大量符合条件的冷数据进行了转EC存储,整个集群的EC文件存储效率(EC物理存储/EC逻辑存储)在1.500 ~ 1.505之间,节省了可观的物理空间。
为数据容灾考虑,01机房的核心数据将每天增量地备份到02机房。这种场景非常适合将02机房数据使用EC存储。其备份流程如下:
通过数据资产平台每天的定时分析,获得01机房核心增量数据
自研的Anty系统将增量核心数据通过定制的distcp写到02机房存储为EC文件
图7 核心数据跨机房备份流程示意图
▍3.遇到的问题及解决办法
在EC存储落地的过程中,我们遇到过一些问题,有些问题社区高版本已经解决,有些问题我们已提给社区。这里,我们列举一些典型的问题做简要说明。
在转EC的过程中,偶现客户端线程hang住问题。详情见(HDFS-15398)。
下线过程中,在某些场景下触发DN下线失败问题。详情见(HDFS-14920、HDFS-14847)。
DN由于读超时出现NPE,使用脏数据重构EC块问题。引入(HDFS-15240)解决。
线上出现StandbyNN内存偏高问题。经MAT及监控指标(dfs.FSNamesystem.PendingDataNodeMessageCount)发现PendingDataNodeMessages类存在内存泄露,如图8。引入(HDFS-14687)解决。
图8 standby PendingDataNodeMessages内存泄露示意图
相比3副本存储,EC存储也有一些不足的地方,如读写性能有损失(滴滴暂未开启intel isa-l加速库)、小文件不适合转EC等。HDFS EC还处于发展的第一阶段,社区也在持续优化,滴滴内部也紧跟社区步伐。相信随着HDFS社区的不断发展,越来越多的公司将受益于EC技术。
参考文献:
[1] https://issues.apache.org/jira/browse/HDFS-7285
Java与大数据架构
7年老码农,10W关注者。【Java与大数据架构】全面分享Java编程、Spark、Flink、Kafka、Elasticsearch、数据湖等干货。
8篇原创内容
Official Account