Spark内核源码解析十四:checkpoint原理剖析

Checkpoint,是Spark提供的一个比较高级的功能。有的时候啊,比如说,我们的Spark应用程序,特别的复杂,然后呢,从初始的RDD开始,到最后整个应用程序完成,有非常多的步骤,比如超过20个transformation操作。而且呢,整个应用运行的时间也特别长,比如通常要运行1~5个小时。
在上述情况下,就比较适合使用checkpoint功能。因为,对于特别复杂的Spark应用,有很高的风险,会出现某个要反复使用的RDD,因为节点的故障,虽然之前持久化过,但是还是导致数据丢失了。那么也就是说,出现失败的时候,没有容错机制,所以当后面的transformation操作,又要使用到该RDD时,就会发现数据丢失了(CacheManager),此时如果没有进行容错处理的话,那么可能就又要重新计算一次数据。

简而言之,针对上述情况,整个Spark应用程序的容错性很差。

所以,针对上述的复杂Spark应用的问题(没有容错机制的问题)。就可以使用checkponit功能。

checkpoint功能是什么意思?checkpoint就是说,对于一个复杂的RDD chain,我们如果担心中间某些关键的,在后面会反复几次使用的RDD,可能会因为节点的故障,导致持久化数据的丢失,那么就可以针对该RDD格外启动checkpoint机制,实现容错和高可用。

checkpoint,就是说,首先呢,要调用SparkContext的setCheckpointDir()方法,设置一个容错的文件系统的目录,比如说HDFS;然后,对RDD调用调用checkpoint()方法。之后,在RDD所处的job运行结束之后,会启动一个单独的job,来将checkpoint过的RDD的数据写入之前设置的文件系统,进行高可用、容错的类持久化操作。

那么此时,即使在后面使用RDD时,它的持久化的数据,不小心丢失了,但是还是可以从它的checkpoint文件中直接读取其数据,而不需要重新计算。(CacheManager)

1、如何进行checkpoint?
SparkContext.setCheckpointDir()
RDD.checkpoint()
2、Checkpoint原理剖析
3、Checkpoint与持久化的不同:lineage的改变
4、RDD.iterator():读取checkpoint数据
5、给要checkpoint的RDD,先进行persist(StorageLevel.DISK_ONLY)

 

 

 

 rdd的iterator方法

/**
   * Internal method to this RDD; will read from cache if applicable, or otherwise compute it.
   * This should ''not'' be called by users directly, but is available for implementors of custom
   * subclasses of RDD.
   * 先persist()再checkpoint(),那么首先执行到该rdd的iterator之后,会先发现storageLevel!=StorageLevel。NONE
   * 那么就会通过CacheManager去获取数据,此时会通过BlockManager获取不到数据,就会第一次计算该rdd的数据,然后通过cacheManager
   * putInBlockManager()将其通过BlockManager进行持久化,rdd所在job运行结束后,启动单独的job进行checkpoint操作,此时又会执行
   * 该rdd的iteratro方法,那么就会发现持久化不为空,默认从blockManager读取数据,正常情况能读到数据,非正常情况下文件损坏读取不到数据
   * 就会从新computeOrReadCheckpoint,判断父rdd的ischeckpoint是否为true,是就会调用父rdd的iterator方法
   */
  final def iterator(split: Partition, context: TaskContext): Iterator[T] = {
    // 如果持久化级别不是none,之前持久化过RDD,那么就不要直接去执行父RDD的算子,
    // 计算新的RDD的Partition优先采用cacheManager去获取持久化的数据
    if (storageLevel != StorageLevel.NONE) {
      SparkEnv.get.cacheManager.getOrCompute(this, split, context, storageLevel)
    } else {
      computeOrReadCheckpoint(split, context)
    }
  }

checkpointRDD的compute方法

// 调用
  override def compute(split: Partition, context: TaskContext): Iterator[T] = {
    val file = new Path(checkpointPath, CheckpointRDD.splitIdToFile(split.index))
    CheckpointRDD.readFromFile(file, broadcastedConf, context)
  }

 

posted on 2020-05-19 01:02  清浊  阅读(239)  评论(0编辑  收藏  举报