Spark Streaming 的 checkpoint 目的是保证长时间运行的任务在意外挂掉后保证数据不丢失,checkpoint 包含两种数据:metadata 和 data,本篇主要讨论对 metadata 的 checkpoint。

如何checkpoint

如果要对 metadata 做 checkpoint,首先要有一个可靠的文件系统保证数据的安全性,spark 支持 hdfs 等。通过代码streamingContext.checkpoint(checkpointDirectory)指定具体的存储路径;

jobGenerator 在每一个 batch 时间后调用 generateJobs 方法,在 jobScheduler.submitJobSet 提交任务后,执行 doCheckpoint 方法来保存 metadata ;

doCheckpoint 方法中先判断是否需要 checkpoint ,条件为 ssc.checkpointDuration != null && ssc.checkpointDir != null ,最重要的是指定后面的 ssc.checkpointDir 指定路径,再判断是否到时间,如果满足条件进行正式代码;

通过 ssc.graph.updateCheckpointData(time) 调用 DStream 的updateCheckpointData,从而执行每个DStream子类的checkpointData.update(currentTime),以DirectKafkaInputDStream为例,最后执行的是DirectKafkaInputDStreamCheckpointData的update,目的是更新要持久的源数据checkpointData.data;通过dependencies.foreach(_.updateCheckpointData(currentTime))使所有依赖的DStream执行;

spark metadata spark metadata方法_spark metadata

所有DStream都执行完update后,执行CheckpointWriter.write(new Checkpoint(ssc, time), clearCheckpointDataLater),本次batchcheckpoint完成;

当 jobGenerator 接收到 batch 完成事件后,通过 jobGenerator.onBatchCompletion(jobSet.time) 调用 clearMetadata 方法,最后执行 DStream 的 clearMetadata 删除 generatedRDDs 的过期 RDD 的metadata。

如何恢复

要从 checkpoint 中恢复,在创建 StreamingContext 时略有不同,代码如图

spark metadata spark metadata方法_spark metadata_02

StreamingContext 的 getOrCreate 方法中,先通过 CheckpointReader.read( checkpointPath, new SparkConf(), hadoopConf, createOnError) 反序列化出 Checkpoint,如果 Checkpoint 不为空即路径存在且有数据,使用 StreamingContext(null, _, null) 构造方法创建 StreamingContext;

StreamingContext.start 后,在使用 DStreamGraph 的实例时时会判断此实例为新创建或从 checkpoint 中恢复,如从 checkpoint 中恢复,则执行 graph.restoreCheckpointData(), 通过 DStream 的 restoreCheckpointData 最终调用 DStream 子类内部的 DStreamCheckpointData.restore 将保存的 RDD metadata 写回到 generatedRDDs 里;

同时 jobGenerator 在 start 时,判断 ssc.isCheckpointPresent,实际就是判断 ssc 里面的 cp_ 是否有值从而执行 restart 方法。restart 方法首先从 checkpoint 的时间开始恢复任务,然后生成从最后时间到 restartTime 时间序列;

spark metadata spark metadata方法_spark metadata_03

调用 graph.generateJobs 生成 job ,在方法内会调用 DStream 的 generateJobs时,在 getOrCompute 方法通过上面还原的 generatedRDDs获取对应时间的 RDD 源数据信息,如果没有再重新生成,最后提交任务。

spark metadata spark metadata方法_spark metadata_04

创建与恢复区别

先看一下Checkpoint中包括哪些信息:

val master = ssc.sc.master
val framework = ssc.sc.appName
val jars = ssc.sc.jars
val graph = ssc.graph
val checkpointDir = ssc.checkpointDir
val checkpointDuration = ssc.checkpointDuration
val pendingTimes = ssc.scheduler.getPendingTimes().toArray
val delaySeconds = MetadataCleaner.getDelaySeconds(ssc.conf)
val sparkConfPairs = ssc.conf.getAll

以上数据都是通过反序列化恢复得到的,对新程序的所有的配置都不会生效,比如队列、资源数等。

恢复 checkpoint 时,从文件系统反序列化数据成 CheckPoint 的具体代码为 Checkpoint.deserialize(fis, conf),所以还原的信息要与当前编译的 serialVersion 一致,否则会出现异常

在 jobGenerator 中,新创建的 StreamingContext 调用的是 startFirstTime 方法,会初始化 DStream 的一些数据;而 checkpoint 恢复调用的是 restart。