【Spark】Spark容错机制

引入

一般来说,分布式数据集的容错性有两种方式:数据检查点和记录数据的更新
面向大规模数据分析,数据检查点操作成本非常高,须要通过数据中心的网络连接在机器之间复制庞大的数据集,而网络带宽往往比内存带宽低得多,同一时候还须要消耗很多其它的存储资源。


因此,Spark选择记录更新的方式。可是,假设更新粒度太细太多,那么记录更新成本也不低。因此。RDD仅仅支持粗粒度转换,即仅仅记录单个块上运行的单个操作,然后将创建RDD的一系列变换序列(每一个RDD都包括了他是怎样由其它RDD变换过来的以及怎样重建某一块数据的信息。因此RDD的容错机制又称“血统(Lineage)”容错)记录下来,以便恢复丢失的分区。
Lineage本质上非常相似于数据库中的重做日志(Redo Log),仅仅只是这个重做日志粒度非常大,是对全局数据做相同的重做进而恢复数据。

Lineage机制

Lineage简单介绍

相比其它系统的细颗粒度的内存数据更新级别的备份或者LOG机制,RDD的Lineage记录的是粗颗粒度的特定数据Transformation操作(如filter、map、join等)行为。

当这个RDD的部分分区数据丢失时,它能够通过Lineage获取足够的信息来又一次运算和恢复丢失的数据分区。由于这样的粗颗粒的数据模型,限制了Spark的运用场合,所以Spark并不适用于全部高性能要求的场景,但同一时候相比细颗粒度的数据模型,也带来了性能的提升。

两种依赖关系

RDD在Lineage依赖方面分为两种:窄依赖(Narrow Dependencies)与宽依赖(Wide Dependencies,源代码中称为Shuffle
Dependencies),用来解决数据容错的高效性。

  • 窄依赖是指父RDD的每一个分区最多被一个子RDD的分区所用,表现为一个父RDD的分区相应于一个子RDD的分区
    或多个父RDD的分区相应于一个子RDD的分区,也就是说一个父RDD的一个分区不可能相应一个子RDD的多个分区。
    1个父RDD分区相应1个子RDD分区,这当中又分两种情况:1个子RDD分区相应1个父RDD分区(如map、filter等算子),1个子RDD分区相应N个父RDD分区(如co-paritioned(协同划分)过的Join)。
  • 宽依赖是指子RDD的分区依赖于父RDD的多个分区或全部分区,即存在一个父RDD的一个分区相应一个子RDD的多个分区。
    1个父RDD分区相应多个子RDD分区,这当中又分两种情况:1个父RDD相应全部子RDD分区(未经协同划分的Join)或者1个父RDD相应非全部的多个RDD分区(如groupByKey)。

本质理解:依据父RDD分区是相应1个还是多个子RDD分区来区分窄依赖(父分区相应一个子分区)和宽依赖(父分区相应多个子分
区)。假设相应多个,则当容错重算分区时,由于父分区数据仅仅有一部分是须要重算子分区的,其余数据重算就造成了冗余计算。

对于宽依赖。Stage计算的输入和输出在不同的节点上,对于输入节点完善。而输出节点死机的情况。通过又一次计算恢复数据这样的情况下,这样的方法容错是有效的,否则无效。由于无法重试,须要向上追溯其祖先看能否够重试(这就是lineage,血统的意思),窄依赖对于数据的重算开销要远小于宽依赖的数据重算开销。

窄依赖和宽依赖的概念主要用在两个地方:一个是容错中相当于Redo日志的功能;还有一个是在调度中构建DAG作为不同Stage的划分点。

依赖关系的特性

第一,窄依赖能够在某个计算节点上直接通过计算父RDD的某块数据计算得到子RDD相应的某块数据;宽依赖则要等到父RDD全部数据都计算完毕之后,并且父RDD的计算结果进行hash并传到相应节点上之后才干计算子RDD。
第二,数据丢失时,对于窄依赖仅仅须要又一次计算丢失的那一块数据来恢复。对于宽依赖则要将祖先RDD中的全部数据块全部又一次计算来恢复。所以在长“血统”链特别是有宽依赖的时候,须要在适当的时机设置数据检查点。

也是这两个特性要求对于不同依赖关系要採取不同的任务调度机制和容错恢复机制。

容错原理

在容错机制中,假设一个节点死机了。并且运算窄依赖。则仅仅要把丢失的父RDD分区重算就可以,不依赖于其它节点。而宽依赖须要父RDD的全部分区都存在,重算就非常昂贵了。

能够这样理解开销的经济与否:在窄依赖中。在子RDD的分区丢失、重算父RDD分区时,父RDD相应分区的全部数据都是子RDD分区的数据,并不存在冗余计算。

在宽依赖情况下,丢失一个子RDD分区重算的每一个父RDD的每一个分区的全部数据并非都给丢失的子RDD分区用的,会有一部分数据相当于相应的是未丢失的子RDD分区中须要的数据,这样就会产生冗余计算开销,这也是宽依赖开销更大的原因。因此假设使用Checkpoint算子来做检查点,不仅要考虑Lineage是否足够长,也要考虑是否有宽依赖,对宽依赖加Checkpoint是最物有所值的。

Checkpoint机制

通过上述分析能够看出在下面两种情况下,RDD须要加检查点。

  1. DAG中的Lineage过长,假设重算,则开销太大(如在PageRank中)。
  2. 在宽依赖上做Checkpoint获得的收益更大。

由于RDD是仅仅读的,所以Spark的RDD计算中一致性不是主要关心的内容,内存相对easy管理,这也是设计者非常有远见的地方,这样降低了框架的复杂性,提升了性能和可扩展性,为以后上层框架的丰富奠定了强有力的基础。


在RDD计算中。通过检查点机制进行容错,传统做检查点有两种方式:通过冗余数据和日志记录更新操作。

在RDD中的doCheckPoint方法相当于通过冗余数据来缓存数据。而之前介绍的血统就是通过相当粗粒度的记录更新操作来实现容错的。

检查点(本质是通过将RDD写入Disk做检查点)是为了通过lineage做容错的辅助。lineage过长会造成容错成本过高。这样就不如在中间阶段做检查点容错,假设之后有节点出现故障而丢失分区。从做检查点的RDD開始重做Lineage,就会降低开销。

转载请注明作者Jason Ding及其出处
GitCafe博客主页(http://jasonding1354.gitcafe.io/)
Github博客主页(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354进入我的博客主页

原文地址:https://www.cnblogs.com/cynchanpin/p/7163160.html