Hadoop 3.0 Erasure Coding 纠删码功能预分析

前言



HDFS也可以支持Erasure Coding功能了,将会在Hadoop 3.0中发布,可以凭图为证:

HDFS-7285中,实现了这个新功能.鉴于此功能还远没有到发布的阶段,可能后面此块相关的代码还会进行进一步的改造,因此只是做一个所谓的预分析,帮助大家提前了解Hadoop社区目前是如何实现这一功能的.本人之前也没有接触过Erasure Coding技术,中间过程也确实有些偶然,相信本文可以带给大家收获.

巧遇Hadoop 3.0 Erasure Coding



第一次主动去了解erasure coding这个东西纯粹是好奇,因为我平时主要混迹于Hadoop社区中HDFS模块部分,经常看到有很多的Issue Summary以单词Erasure Coding打头,而且这些任务一般都隶属于HDFS-8031下的子任务,比如下图所示的1个:

原来这是Erasure coding后续1阶段的工作.然后我就上网查了一下Erasure coding的意思于是就萌生了写此文的意图.Erasure coding同样作为一门技术,在学习hadoop 3.0 erasure coding之前,还是非常有必要去了解学习Erasure coding这门技术.

Erasure coding纠删码



Erasure coding纠删码技术简称EC,是一种数据保护技术.最早用于通信行业中数据传输中的数据恢复,是一种编码容错技术.他通过在原始数据中加入新的校验数据,使得各个部分的数据产生关联性.在一定范围的数据出错情况下,通过纠删码技术都可以进行恢复.下面结合图片进行简单的演示,首先有原始数据n个,然后加入m个校验数据块.如下图所示:

Parity部分就是校验数据块,我们把一行数据块组成为Stripe条带,每行条带由n个数据块和m个校验块组成.原始数据块和校验数据块都可以通过现有的数据块进行恢复,原则如下:

  • 如果校验数据块发生错误,通过对原始数据块进行编码重新生成
  • 如果原始数据块发生错误, 通过校验数据块的解码可以重新生成

而且m和n的值并不是固定不变的,可以进行相应调整.可能有人会好奇,这其中到底是什么原理呢? 其实道理很简单,你把上面这图看成矩阵,由于矩阵的运算具有可逆性,所以就能使数据进行恢复,给出一张标准的矩阵相乘图,大家可以将二者关联.

至于里面涉及数学推理的方面,同学们可以自行寻找资料进行学习.

Erasure Coding技术的优劣势


优势

纠删码技术作为一门数据保护技术,自然有许多的优势,首先可以解决的就是目前分布式系统,云计算中采用副本来防止数据的丢失.副本机制确实可以解决数据丢失的问题,但是翻倍的数据存储空间也必然要被消耗.这一点却是非常致命的.EC技术的运用就可以直接解决这个问题.

劣势

EC技术的优势确实明显,但是他的使用也是需要一些代价的,一旦数据需要恢复,他会造成2大资源的消耗:

  • 网络带宽的消耗,因为数据恢复需要去读其他的数据块和校验块
  • 进行编码,解码计算需要消耗CPU资源

概况来讲一句话,就是既耗网络又耗CPU,看来代价也不小.所以这么来看,将此计数用于线上服务可能会觉得不够稳定,所以最好的选择是用于冷数据集群,有下面2点原因可以支持这种选择

  • 冷数据集群往往有大量的长期没有被访问的数据,体量确实很大,采用EC技术,可以大大减少副本数
  • 冷数据集群基本稳定,耗资源量少,所以一旦进行数据恢复,将不会对集群造成大的影响

出于上述2种原因,冷数据集群无非是一个很好的选择.

Erasure Coding技术在Hadoop中的实现



前面花了大量的篇幅介绍EC技术,相信大家已经或多或少了解了这项技术.现在才是本文的一个重点,Hadoop Erasure Coding的实现.因为我们都知道,Hadoop作为一个成熟的分布式系统,用的也是3副本策略,所以这项技术的产生对于Hadoop本身来说,意义还是非常重大的.考虑到EC技术在Hadoop中的实现细节可能比较复杂,所以我不会逐行代码般的进行分析,从大的方向上理一理实现思路.

EC概念在Hadoop中的演变



EC概念指的是data block数据块,parity block校验块,stripe条带等这些概念在HDFS中是如何进行转化的,因为要想实现EC技术,至少在概念上相同的.

  • data block,parity block在HDFS中的展现就是普通的block数据块
  • stripe条带的概念需要将每个block进行分裂,每个block由若干个相同大小的cell组成,然后每个stripe由于一行cell构成,相当于所有的data block和parity block抽取出了一行

下面用图形直观展示

上面的横竖结构可以看出来很像之前提到的矩阵.为什么要有stripe条带概念就是因为矩阵运算就会读到每行的数据.OK,接下来我们放大上面这个图

要对应上面的3种概念,需要设计几种逻辑上的单元概念,有下面2个逻辑概念

  • Block Group的组概,图中蓝色矩阵中的部分,逻辑上代表者一个hdfs文件.
  • cell概念,就是从逻辑上将每个block块进行cell大小的拆分,因为不同block大小不同,所以不同block块的cell数量可能也会不同.

中间的internal blocks才是最终存储数据的block块,也就是我们平常说的HDFS中的block块.

stripe的大小在HDFS中的计算逻辑如下:

// Size of each stripe (only counting data blocks)
final int stripeSize = cellSize * numDataBlocks;

就是一行的大小.获取block长度的实现逻辑如下

    // Size of each stripe (only counting data blocks)
    final int stripeSize = cellSize * numDataBlocks;
    // If block group ends at stripe boundary, each internal block has an equal
    // share of the group
    final int lastStripeDataLen = (int)(dataSize % stripeSize);
    if (lastStripeDataLen == 0) {
      return dataSize / numDataBlocks;
    }

    final int numStripes = (int) ((dataSize - 1) / stripeSize + 1);
    return (numStripes - 1L)*cellSize
        + lastCellSize(lastStripeDataLen, cellSize, numDataBlocks, i);

如果恰好最后一行stripe长度为0,则说明每个block长度相等,直接返回即可,否则还要另外加上lastCellSize的大小.

HDFS Erasure Coding实现



了解了上述提到的概念,就可以开始真正了解ec在hdfs的实现,实现步骤主要在ErasureCodingWorker#ReconstructAndTransferBlock类中.从注释中可以看出,主要分为3大步.

  • step1: read bufferSize data from minimum number of sources required by reconstruction.
  • step2: decode data for targets.
  • step3: transfer data to targets.

现在我们一步一步的来看.

Step1

看官方注释中对第一步骤的描述:

   In step1, try to read bufferSize data from minimum number of sources , if there is corrupt or stale sources, read from new source will be scheduled. The best sources are remembered for next round and may be updated in each round.

概况的说,就是他首先会从sources node源节点中选出符合最好的n个节点,如果节点中有坏的或是慢节点,则会重新进行选择一次,代码如下

    // step1: read from minimum source DNs required for reconstruction.
    // The returned success list is the source DNs we do real read from
    Map<ExtendedBlock, Set<DatanodeInfo>> corruptionMap = new HashMap<>();
    try {
        success = readMinimumStripedData4Reconstruction(success,
        toReconstruct, corruptionMap);
    } finally {
        // report corrupted blocks to NN
        reportCorruptedBlocks(corruptionMap);
    }

然后会对每个source node新建相应的striperReader进行远程读,远程读会用到striperReader的blockReader和buffer缓冲.

    private StripedReader addStripedReader(int i, long offsetInBlock) {
      final ExtendedBlock block = getBlock(blockGroup, liveIndices[i]);
      StripedReader reader = new StripedReader(liveIndices[i], block, sources[i]);
      stripedReaders.add(reader);

      BlockReader blockReader = newBlockReader(block, offsetInBlock, sources[i]);
      if (blockReader != null) {
        initChecksumAndBufferSizeIfNeeded(blockReader);
        reader.blockReader = blockReader;
      }
      reader.buffer = allocateBuffer(bufferSize);
      return reader;
    }

图形展示效果如下

因为第一步骤的子步骤比较多一些,所以我制作了执行顺序图

Step2

同样给出官方源码注释

  In step2, typically if source blocks we read are all data blocks, we need to call encode, and if there is one parity block, we need to call decode. Notice we only read once and reconstruct all missed striped block
if they are more than one.

第二个步骤主要在于编解码数据的过程.第一个步骤已经把数据读到缓冲区了,第二步就是计算的过程了.这里提到了很关键的一点.

if source blocks we read are all data blocks, we need to call encode, and if there is one parity block, we need to call decode.

编解码的决定要依靠于恢复的对象决定的,与之前在上半篇幅中提到的原则是一致的.相关代码如下

   // step2: decode to reconstruct targets
   reconstructTargets(success, targetsStatus, toReconstruct);
    ...
    int[] erasedIndices = getErasedIndices(targetsStatus);
    ByteBuffer[] outputs = new ByteBuffer[erasedIndices.length];
    int m = 0;
    for (int i = 0; i < targetBuffers.length; i++) {
      if (targetsStatus[i]) {
        targetBuffers[i].limit(toReconstructLen);
        outputs[m++] = targetBuffers[i];
      }
    }
    decoder.decode(inputs, erasedIndices, outputs);
...

但是在这里我有一点疑惑,这里直接使用的decode解码的操作,可能在这种使用场景下都是解码的情况.

Step3

第三步骤就很简单了,就是transfering data的操作,将buffer中的缓冲数据写入到目标节点即可.

  In step3, send the reconstructed data to targets by constructing packet and send them directly. Same as continuous block replication, we don‘t check the packet ack. Since the datanode doing the reconstruction work are one of the source datanodes, so the reconstructed data are sent remotely.

写的方式很简单,直接远程写即可,因为此类写操作只涉及到1个节点,无须构建后续pipeline的动作.此方面可以阅读我的另外一篇博文从DFSOutputStream的pipeline写机制到Streamer线程泄漏问题.

    // step3: transfer data
    if (transferData2Targets(targetsStatus) == 0) {
        String error = "Transfer failed for all targets.";
        throw new IOException(error);
    }

OK,以上就是Hadoop 3.0中EC数据恢复技术的一个主要实现.一张完整的顺序图如下

改进优化点



在官方注释中已经提到了2个改进点,在后续应该会被完善.

  • 目前的数据没有采用本地读的方式,一律用远程方式进行数据读取.
  • 目标数据恢复传输没有返回packet数据包的ack确认码,不像pipeline那样有很健全的一套体系.

相关链接



在学习Erasure Coding技术的过程中,查看了很多的资料,并且提交了一个Issue给社区,HDFS-9832,大家都可以看看.顺便说一句,我是去年9月开始接触Hadoop社区的,参与开源的过程使我对Hadoop的了解程度比以往更加深入了一层,这点感受确实很深.目前Hadoop最快的已经在开发3.0的版本了,而目前apache发布的最高版本是2.7.2,中间还有2.7.3, 2.8.0, 2.9.0等版本,所以Hadoop 3.0的问世还需要一段时间,而且在3.0中还会有许多新功能和旧的功能大改.目前Hadoop社区做的人主要是北美时区的人,大多是cloudera,hortonworks,apache下的人在做,偶有个别huawei的人也在做.希望大家多多参与开源,了解开源,向开源社区做出自己的贡献.

1.wiki Erasure Coding: https://en.wikipedia.org/wiki/Erasure_code

2.http://www.searchstorage.com.cn/whatis/word_6080.htm

3.http://blog.sina.com.cn/s/blog_3fe961ae0102vpxr.html

4.Issue 链接: https://issues.apache.org/jira/browse/HDFS-9832

5.Github patch链接:

https://github.com/linyiqun/open-source-patch/tree/master/hdfs/HDFS-9832

时间: 2024-08-25 18:15:37

Hadoop 3.0 Erasure Coding 纠删码功能预分析的相关文章

分布式系统下的纠删码技术(一) -- Erasure Code (EC)

近几个月主要参与一个分布式存储系统的纠删码部分(用于数据容错),纠删码在学术界出现比较早,现在ceph,微软的存储系统,Hadoop 3.0等都用了EC.文章会分为多篇,主要将Erasure Code,LRC,  以及相关的数学基础,作为学习总结. 一.纠删码简介 分布式系统需要在硬件失效等故障发生后仍然能继续提供服务.就数据而言,HDFS采用每份数据3副本的方式,保证某些数据损失之后仍能继续使用. 数据的容错除了副本还有另一种做法,就是把丢失的数据计算出来.这就是纠删码的思想了.(PS: Sp

MICS:副本和纠删码混合存储系统

摘要 云存储系统的三个指标: 高可靠性,低存储开销,高读写性能. 这三个指标是没有办法同一时候满足的,许多时候须要进行tradeoff. 副本系统和纠删码是两种在存储系统中广泛使用的策略,它们在保证高可靠性的前提下,选择了不同极端的tradeoff. 副本存储开销大,但性能较好.纠删码存储开销低.但性能较差.本文提出了MICS系统.它将一个对象以两种形式存储,一种採用副本.一种採用分片纠删码,不仅如此.还设计了针对这种hyprid结构的精细的读写协议. 在服务使用者的角度.MICS通过PRAM一

浅谈Ceph纠删码

目  录第1章 引言 1.1 文档说明 1.2 参考文档 第2章 纠删码概念和原理 2.1 概念 2.2 原理 第3章 CEPH纠删码介绍 3.1 CEPH纠删码用途 3.2 CEPH纠删码库 3.3 CEPH纠删码数据存储 3.3.1 编码块读写 3.3.2 间断全写 3.4 使用范围 3.4.1 冷数据 3.4.2 廉价多数据中心存储 第4章 CEPH纠删码实例 4.1 数据读写 4.2 纠删码池不支持部分功能 4.3 纠删码PROFILE 4.4 CECHE TIER弥补ERASURE的缺

纠删码简介

纠删码(Erasure Code)中的数学知识 背景 在数据存储领域,Hadoop采用三副本策略有效的解决了存储的容错问题,但是三副本策略中磁盘的利用效率比较低,仅有33%,而且副本带来的成本压力实在太高,后来适时的出现了纠删码的概念.当冗余级别为n+m时,将这些数据块分别存放在n+m个硬盘上,这样就能容忍m个(假设初始数据有n个)硬盘发生故障.当不超过m个硬盘发生故障时,只需任意选取n个正常的数据块就能计算得到所有的原始数据.纠删码以更低的存储成本备受青睐,目前Microsoft.Google

[转]Reed Solomon纠删码

http://peterylh.blog.163.com/blog/static/12033201371375050233/ 纠删码是存储领域常用的数据冗余技术, 相比多副本复制而言, 纠删码能够以更小的数据冗余度获得更高数据可靠性. Reed Solomon Coding是存储领域常用的一种纠删码,它的基本原理如下:  给定n个数据块d1, d2,..., dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,..., cm.  对于任意的n和m,  从n个原始数据块和m

如何选择纠删码编码引擎 | 纠删码技术详解(上)

作者介绍: 徐祥曦,七牛云工程师,独立开发了多套高性能纠删码/再生码编码引擎.柳青,华中科技大学博士,研究方向为基于纠删码的分布式存储系统. 前言:随着数据的存储呈现出集中化(以分布式存储系统为基础的云存储系统)和移动化(互联网移动终端)的趋势,数据可靠性愈发引起大家的重视.集群所承载的数据量大大上升,但存储介质本身的可靠性进步却很小,这要求我们必须以更加经济有效的方式来保障数据安全. 副本与纠删码都是通过增加冗余数据的方式来保证数据在发生部分丢失时,原始数据不发生丢失.但相较于副本,纠删码能以

纠删码简要介绍(与纠错码的区别)

存储领域来看,数据冗余机制其实这几十年来没有太多进展,RAID,副本一直是当仁不让的最终选择.而近几年,尤其是规模较大的应用场景下,纠删码越来越多的出现在选择的视野范围,成为RAID,副本之外的第三种选择,因此也获得了越来越多的关注. 纠删码(Erasure Code)本身是一种编码容错技术,最早是在通信行业解决部分数据在传输中损耗的问题,它的基本原理是把传输的信号分段,加入一定的校验再让各段间发生一定的联系,即使在传输过程中丢失掉部分信号,接收端仍然能通过算法把完整的信息计算出来.如果严格的区

实现高性能纠删码引擎 | 纠删码技术详解(下)

作者介绍: 徐祥曦,七牛云工程师,独立开发了多套高性能纠删码/再生码编码引擎.柳青,华中科技大学博士,研究方向为基于纠删码的分布式存储系统. 前言: 在上篇<如何选择纠删码编码引擎>中,我们简单了解了 Reed-Solomon Codes(RS 码)的编/解码过程,以及编码引擎的评判标准.但并没有就具体实现进行展开,本篇作为<纠删码技术详解>的下篇,我们将主要探讨工程实现的问题. 这里先简单提炼一下实现高性能纠删码引擎的要点:首先,根据编码理论将矩阵以及有限域的运算工程化,接下来主

Ceph纠删码编码机制调研

1 Ceph简述 Ceph是一种性能优越,可靠性和可扩展性良好的统一的分布式云存储系统,提供对象存储.块存储.文件存储三种存储服务.Ceph文件系统中不区分节点中心,在理论上可以实现系统规模的无限扩展.Ceph文件系统使用了较为简单的数据地址管理方法,通过计算的方式直接得到数据存放的位置.其客户端程序只需要根据数据ID经过简单的计算就可以决定数据存放的位置. 2 存储容错机制简述 2.1 副本冗余容错机制 基于副本冗余的容错机制是将原始数据复制成多份,每一份称为一个副本.将这些副本分别存放在集群