在之前我的一篇文章中,已经聊到过一次关于HDFS EC方面的内容(文章链接Hadoop 3.0 Erasure Coding 纠删码功能预分析),所以本文算是对其内容的一次补充.之前的文章中主要是从宏观的层面上阐述了HDFS EC的作用以及相应的使用场景,并没有深入到内部相关架构设计以及具体EC算法的的内容.本文主要=阐述的内容正在于这两方面.
EC是Erasure Coding的缩写,中文名叫做纠删码,是一种能够进行数据错误纠正的技术.EC比较常见的一个使用场景是用于信号通信传输方面.在数据通信过程中,数据信号发生错误是时有发生的事情,EC编码技术是如何做到数据自动纠正的呢?这里就不得不引出EC中使用非常广泛的一个算法:XOR码.
XOR是”异或”的意思,XOR码的原理如下:
数据编码时按照位进行异或运算,数据恢复的时候也就是解码时则通过结果与其他数据位进行异或操作的逆运算.
异或操作与我们常见的”与”操作和”或”操作略有不同,遵循”相同为0,不同则为1”的运算原则.比如下面的例子(⊕就是异或操作的意思):
1 ⊕ 1 = 0;
0 ⊕ 0 = 0;
1 ⊕ 0 = 1;
0 ⊕ 1 = 1;
0 ⊕ 1 ⊕ 1 = 0;
现在假设最后一个式子中的第二位,就是数字第一个数字1丢失了,变成了下面这个式子:
0 ⊕ ? ⊕ 1 = 0;
我们可以通过异或操作的逆运算恢复数据,因为最后结果为0,所以0 ⊕ ?的结果应该为1,也就是0 ⊕ ? = 1,因为异或运算,不同才为1,所以这里丢失的数据就是1,数据成功恢复.但是这里暴露出了一个问题,如果丢失或损坏的数据位超过1位的时候,数据好像就不是那么好恢复了,比如丢失了头2位:
? ⊕ ? ⊕ 1 = 0;
这个时候头2位是0,1还是1,0呢?只能说都有可能.OK,从这里我们可以看出XOR编码算法存在可容忍错误过少的问题,那么有什么别的EC算法能帮我们解决这个问题呢?在很多场合下,是会存在多个数据丢失的情况的,并不能确保每次只有1个数据出错的情况.下面介绍的新的编码算法能解决这个棘手的问题.
Reed-Solomon Codes也是EC编码中的一种.Reed-Solomon Codes缩写为RS码,中文名称里德所罗门码.下面说说RS码在HDFS中的使用原理.RS码在使用的时候需要指定2个参数的,RS(k, m),k代表的是data cell数据块的数量,m代表的是parity cell块的数量,parity cell可理解为加密块,因为它是由数据块编码产生的.RS码的恢复原理如下:
数据块如果发生损坏,则可以通过parity cell和其他data cell的解码计算重新恢复.
如果加密块发生损坏,则可以通过data cell重新进行编码生成.
以上数据块与加密块的编解码原理与矩阵运算有点关联,感兴趣的同学可以查阅相关资料继续学习.注意了,以上数据块出错的最大容忍数为m.不过这个数字我们可以进行调整,比如RS(6, 3)或RS(10, 4)等.这里的数据块与加密块的存储方式与传统的数据存放方式略有不同,它是横向式的条带式存储,而不是传统的连续存储方式.可能这句话有点难懂,没有关系,我们继续看下文,后面将给出详细的解释.
从这节开始,我们慢慢将主题转到HDFS的EC上来.不管是连续存储方式也好,还是EC的条带式存储,其实都是属于Block Layout布局上面的问题.下面我们来仔细分析这2种方式的布局特点.
连续存储方式就是我们平常所熟知的HDFS的文件存储方式,以Block块为单位,如果文件写数据大小超出了1个块,则新创建一个块继续写,知道写完整个数据.整个存储的逻辑结构如下图所示:
上图是标准的128M一个块大小的连续存储图.想要进一步学习HDFS连续存储方面的内容可以查看相关类BlockInfoContiguous,或点击查看我的另外一篇文章HDFS邻近信息块BlockInfoContiguous.
Stripe在这里的意思就是条带式的意思.我第一次看到HDFS中的条带式存储方式时候,我的第一感觉是这种存储逻辑看起来非常的别扭.虽然说它还是以Block作为一个存储的单元,但是数据是横向式的保存在各个Block上.换句话说,同一个Block上的不同分段的数据是完全不连续的.条带式的存储结构图如下:
在每个Block块中的一个横块,就是上文讲述RS码时的data cell的概念.下面是基于HDFS下的data cell结合parity cell加密块的条带式存储的展示效果图:
上图对应的EC编码类型是RS(6, 3).前面从DataNode0~5总共6个节点存数据块,后面的DataNode6~8存的则是加密块.其实我们可以看到,HDFS EC的独有的条带式的存储方式与原有的存储方式存在着非常大的不同.这势必会带来数据读写方式的改变.而HDFS EC是如何做到其中的适配呢?还有一个问题,HDFS EC下的数据能支持原来的许多的HDFS的一些特性吗,Snapshot?EncryptionZone?HDFS Cache?
前面说了这么多,最后终于要提到HDFS EC的架构设计了.我想这也是很多关注HDFS EC的人想要了解的.EC纠删码技术作为一项数据保护技术,本身存在一定的学习成本,要把它引入到HDFS中,也绝对不是一件简单的事情.要做非常多的适配改造工作.想要了解更加详细的架构设计部分,可以参见社区上的关于HDFS EC的设计文档,链接点进去即可.下面是本人经过浓缩概况后的内容.
在之前小节的末尾已经提到过,Striping条带式存储方式的引入会带来数据读写逻辑的转变,所以这里需要引入针对HDFS EC特有的条带式的输入输出数据流的读写类.主要是下图所示的几个类:
通过类名称我们也可以直接看出它是适用于哪一类存储方式的数据读写.这里额外提一下ErasureCodingWork的服务,ErasureCodingWork与ReplicationWork类似,它的作用是将新的待复制的副本块任务分配到对应的DataNode节点上.ErasureCodingWork则对应的是分配EC编码任务到相应的DataNode节点上.
HDFS EC的架构设计同样遵从主从结构,有一个中心的管理对象(ECManager),然后有对应的worker对象(ECWorker).这2大角色类有明确的分工.
ECManager:EC管理对象会做许多事情,比如协调数据恢复,健康检测,blockGroup的管理等等.
ECWorker:做的事情很直接,就是EC数据恢复相关的操作.
那么现在有一个问题,我在做EC数据恢复的时候,如何使用之前的EC编码算法呢?HDFS是通过EC Policy进行控制的,每个EC策略对应一种ECSchema参数配置的EC算法.同时这些EC Policy策略对象被ErasureCodingPolicyManager对象所掌管.目前ErasureCodingPolicyManager对象中维护了以下3种EC策略:
private static final ErasureCodingPolicy SYS_POLICY1 =
new ErasureCodingPolicy(ErasureCodeConstants.RS_6_3_SCHEMA,
DEFAULT_CELLSIZE, HdfsConstants.RS_6_3_POLICY_ID);
private static final ErasureCodingPolicy SYS_POLICY2 =
new ErasureCodingPolicy(ErasureCodeConstants.RS_3_2_SCHEMA,
DEFAULT_CELLSIZE, HdfsConstants.RS_3_2_POLICY_ID);
private static final ErasureCodingPolicy SYS_POLICY3 =
new ErasureCodingPolicy(ErasureCodeConstants.RS_6_3_LEGACY_SCHEMA,
DEFAULT_CELLSIZE, HdfsConstants.RS_6_3_LEGACY_POLICY_ID);
以上几个对象的上下层级关系图如下:
综上所述,最后给出HDFS EC设计文档中的总架构设计图:
EC的使用也是非常的方便,能够通过外部命令的方式直接对指定路径下的数据做EC/Replication之间的灵活装换.还能设置不同path下的不同EC Policy,具体EC的使用同样可以参阅HDFS EC的设计文档.总的来看,HDFS EC将会是一个很实用的功能.
1.http://blog.cloudera.com/blog/2015/09/introduction-to-hdfs-erasure-coding-in-apache-hadoop/
2.https://issues.apache.org/jira/secure/attachment/12697210/HDFSErasureCodingDesign-20150206.pdf
3.百度百科.Reed-Solomon Codes.