Spark错误容忍机制

Spark错误容忍机制

1 错误产生的表现和原因

表现:task长时间无响应,内存溢出、IO异常和数据丢失等

原因:硬件问题比如节点宕机、网络阻塞和硬盘损坏等;软件问题比如内存资源分配不足、partition配置过少导致task处理的数据规模太大,partition换份不当引起的数据倾斜,以及用户和系统bug等。

由于错误种类和原因的多样性,因此Spark难以对每种错误都进行容忍与修复,因此需要设计一个与用户无关、自动化且能覆盖多种错误类型的错误容忍机制。

2 设计思想

  1. 通过重新执行计算任务来容忍错误。当Job抛出异常不能继续执行时,重新启动计算任务,再次执行。
  2. 通过采用checkpoint机制,对一些重要的输入/输出、中间数据进行持久化。这可以在一定程度上解决数据丢失问题,而且能够提高任务重新计算时的效率。

3 重新计算机制

3.1 重新计算能得到之前一样结果的保证

  1. 重新计算时,task输入数据与之前是一致的
  2. task的计算逻辑需要满足确定性
  3. task的计算逻辑需要满足幂等性

3.2 计算位置

根据lineage这种数据溯源方法来确定重新计算的位置。在每个RDD中记录上游数据是什么,以及当前RDD是如果通过上游数据(partent RDD)计算得到的。

lineage通俗来讲,就是computation chain(计算链),如果计算链上存在缓存数据,那么从缓存数据处截断计算链,即可得到简化后的操作。不管当前RDD本身就是缓存数据还是非缓存数据,都可以通过lineage回溯方法找到计算该缓存数据所需的操作和数据。

4 checkpoint机制

重新计算有一个很大的缺点,如果某个RDD的计算链路过长,那么重新计算该数据的代价非常高(比如迭代型应用)。为了更好的解决这个问题,为提高重新计算的效率,也为了解决数据丢失问题,设计了checkpoint机制。该机制的核心思想是将计算过程中某些重要数据进行持久化,这样在再次执行时可以从检查点执行,从而减少重新计算的开销。

需要被checkpoint的RDD满足的特征是,RDD的数据依赖关系比较复杂且重新计算代价较高,如关联的数据过多、计算链过长、被多次重复使用等。

checkpoint时机和计算顺序

Spark采用的方法:用户设置rdd.checkpoint()后标记某个RDD需要持久化,计算过程也像正常一样计算,等到当前job计算结束是再重新启动该job计算一遍,对其中需要checkpoint的RDD进行持久化。也就是说,当前job结束后对另外启动专门的job去完成checkpoint,需要checkpoint的RDD会被计算两次。

checkpoint启动额外job来进行持久化会增加计算开销。为了解决这个问题,Spark推荐用户将需要被checkpoint的数据先进行缓存,这样额外启动的人物只需要将缓存数据进行checkpoint即可,不需要重新计算RDD,可以一定程度上提高效率。

checkpoint数据的读取

  1. checkpoint数据格式为序列化的RDD,因此需要进行反序列化重新恢复RDD中的record。
  2. checkpoint时存放了RDD的分区信息,如使用了什么partitioner。这样,重新读取后不仅恢复了RDD数据,也可以恢复其分区方法信息,便于后续操作的数据依赖关系。

checkpoint的实现细节

RDD需要经过 Initialized -> CheckpointingInProgress -> Checkpointed 这3个阶段才能被真正的Checkpoint。

  1. Initialized: 当应用程序使用rdd.checkpoint()设定某个RDD需要被checkpoint时,Spark为该RDD添加一个checkpointData属性,用来管理该RDD相关的checkpoint信息。当程序执行到pairs.checkpoint()时,对pairs.checkpointData对象初始化,该对象保存了pairs的checkpoint的路径及Initialized状态。
  2. CheckpointingInProcess: 当前job结束后,会调用该job最后一个RDD(finalRDD)的doCheckpoint()方法。该方法根据finalRDD的computing chain回溯扫描,遇到需要被chekpoint的RDD就将其标记为CheckpointingInProcess。将pairs.checkpointData的cpState标记为CheckpointingInProcess。之后,Spark会调用runjob()再次跳脚一个job完成checkpoint。
  3. Checkpointed: 再次提交的job对RDD完成checkpoint后,Spark会建立一个newRDD,类型为ReliableCheckpointRDD,用来表示被checkpoint到磁盘上的RDD。newRDD实际就是Checkpointed pairs: RDD,保留了pairs: RDD的分区信息。但与pairs: RDD不同的是,newRDD将lineage截断(dependencies_=null),不再保留pairs依赖的数据和计算,原因是pairs: RDD已被持久化到可靠的分布式文件系统,不需要再保留pairs: RDD是如何计算得到的。newRDD的分区类型为CheckpointedRDDPartition,表示该分区已经被持久化。生成newRDD之后,Spark需要将pairs和newRDD进行关联。当后续job需要读取pairs时,可以去读取newRDD。Spark将newRDD赋值给pairs.checkPointRDD.cpRDD。同时,将pairs的数据依赖关系也清空(本来使用OneToOneDependency依赖inputRDD),因为访问pairs即访问newRDD,而newRDD不需要依赖任何RDD。这个步骤完成后,将pairs.checkPointRDD.cpState的状态设置为Checkpointed。至此,checkpoint的写入过程结束。

chekpoint的写入过程不仅仅是对RDD进行持久化,而且会切断该RDD的lineage,将该RDD与持久化到磁盘上的CheckpointedRDD进行关联。这样,读取该RDD时,即时读取CheckpointedRDD。

5 checkpoint与cache的区别

  1. 目的不同:数据缓存的目的是加速计算,即加速后续运行的job。而checkpoint的目的是在job运行失败后能够快速恢复,也就是说加速当前需要重新运行的job。
  2. 存储性质和位置不同:数据缓存是为了读写速度快,因此主要使用内存,偶尔使用磁盘作为存储空间。而checkpoint是为了能够可靠读写,因此主要使用分布式文件系统作为存储空间。
  3. 写入速度和规则不同:数据缓存速度较快,对job的执行时间影响较小,因此可以在job运行时进行缓存。而checkpoint写入速度慢,为了减少对当前job的时延影响,会额外启动专门的job进行持久化。
  4. 对lineage的影响不同:对某个RDD进行缓存后,对该RDD的lineage没有影响,这样如果缓存后的RDD丢失还可以重新计算得到。而对某些RDD进行checkpoint以后,会切断该RDD的lineage,因为该RDD已经被可靠存储,所以不需要再保留该RDD是如何计算得到的。
  5. 应用场景不同:数据缓存适用于会被多次读取、占用空间不是非常大的RDD,而checkpoint适用于数据依赖关系比较复杂、重新计算代价较高的RDD,如关联的数据过多、计算链过长、被多次重复使用。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值