黑猴子的家:Spark RDD 检查点机制

1、checkpoint

Spark中对于数据的保存除了持久化操作之外,还提供了一种检查点的机制,检查点(本质是通过将RDD写入Disk做检查点)是为了通过lineage做容错的辅助,lineage过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果之后有节点出现问题而丢失分区,从做检查点的RDD开始重做Lineage,就会减少开销。检查点通过将数据写入到HDFS文件系统实现了RDD的检查点功能。
cache 和 checkpoint 是有显著区别的, 缓存把 RDD 计算出来然后放在内存中,但是RDD 的依赖链(相当于数据库中的redo 日志), 血统不能丢掉, 当某个点某个 executor 宕了,上面cache 的RDD就会丢掉, 需要通过 依赖链重新计算出来, checkpoint 是把 RDD 保存在 HDFS中, 是多副本可靠存储,所以依赖链就可以丢掉了,就斩断了依赖链(血统), 是通过复制实现的高容错。


9193428-676ecfe7baf991b0.png
2、比较适合使用检查点机制

如果存在以下场景,则比较适合使用检查点机制

DAG(有向无环图)中的Lineage过长,如果重算,则开销太大(如在PageRank中)。

在宽依赖上做Checkpoint获得的收益更大。

为当前RDD设置检查点。该函数将会创建一个二进制的文件,并存储到checkpoint目录中,该目录是用SparkContext.setCheckpointDir()设置的。在checkpoint的过程中,该RDD的所有依赖于父RDD中的信息将全部被移出。对RDD进行checkpoint操作并不会马上被执行,必须执行Action操作才能触发,懒执行。

3、checkpoint 写流程

RDD checkpoint 过程中会经过以下几个状态,
[ Initialized → marked for checkpointing → checkpointing in progress → checkpointed ]

转换流程如下

9193428-a5c321e06894ac9d.jpg

data.checkpoint 这个函数调用中, 设置的目录中, 所有依赖的 RDD 都会被删除, 函数必须在 job 运行之前调用执行, 强烈建议 RDD 缓存 在内存中(又提到一次,千万要注意哟), 否则保存到文件的时候需要从头计算。初始化RDD的 checkpointData 变量为 ReliableRDDCheckpointData。 这时候标记为 Initialized 状态

在所有 job action 的时候, runJob 方法中都会调用 rdd.doCheckpoint , 这个会向前递归调用所有的依赖的RDD, 看看需不需要 checkpoint。 如果需要 checkpoint, 然后调用 checkpointData.get.checkpoint(), 里面标记 状态为 CheckpointingInProgress, 里面调用具体实现类的 ReliableRDDCheckpointData 的 doCheckpoint 方法

doCheckpoint -> writeRDDToCheckpointDirectory, 注意这里会把 job 再运行一次, 如果已经cache 了,就可以直接使用缓存中的 RDD 了, 就不需要重头计算一遍了(怎么又说了一遍), 这时候直接把RDD, 输出到 hdfs, 每个分区一个文件, 会先写到一个临时文件, 如果全部输出完,进行 rename , 如果输出失败,就回滚delete。

标记 状态为 Checkpointed, markCheckpointed方法中清除所有的依赖, 怎么清除依赖的呢, 就是 吧RDD 变量的强引用 设置为 null, 垃圾回收了,会触发 ContextCleaner 里面监听清除实际 BlockManager 缓存中的数据

4、checkpoint 读流程

如果一个RDD 我们已经 checkpoint了那么是什么时候用呢, checkpoint 将 RDD 持久化到 HDFS 或本地文件夹,如果不被手动 remove 掉,是一直存在的,也就是说可以被下一个 driver program 使用。 比如 spark streaming 挂掉了, 重启后就可以使用之前 checkpoint 的数据进行 recover,当然在同一个 driver program 也可以使用。 我们讲下在同一个 driver program 中是怎么使用 checkpoint 数据的。

如果 一个 RDD 被checkpoint了, 如果这个 RDD 上有 action 操作时候,或者回溯的这个 RDD 的时候,这个 RDD 进行计算的时候,判断如果已经 checkpoint 过, 对分区和依赖的处理都是使用的 RDD 内部的 checkpointRDD 变量。

具体细节如下

如果 一个 RDD 被checkpoint了, 那么这个 RDD 中对分区和依赖的处理都是使用的 RDD 内部的 checkpointRDD 变量, 具体实现是 ReliableCheckpointRDD 类型。 这个是在 checkpoint 写流程中创建的。依赖和获取分区方法中先判断是否已经checkpoint, 如果已经checkpoint了, 就斩断依赖, 使用ReliableCheckpointRDD, 来处理依赖和获取分区。

如果没有,才往前回溯依赖。 依赖就是没有依赖, 因为已经斩断了依赖, 获取分区数据就是读取 checkpoint 到 hdfs目录中不同分区保存下来的文件。

5、案例

RPEL

scala> val rdd = sc.parallelize(1 to 100,5)
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24

scala> sc.setCheckpointDir("hdfs://hadoop102:9000/checkpoint")

scala> rdd.checkpoint

scala> rdd.count
res2: Long = 100                                                                

scala> val ch1 = sc.parallelize(1 to 2)
ch1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[2] at parallelize at <console>:24

scala> val ch2 = ch1.map(_.toString+"["+System.currentTimeMillis+"]")
ch2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[3] at map at <console>:26

scala> val ch3 = ch1.map(_.toString+"["+System.currentTimeMillis+"]")
ch3: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[4] at map at <console>:26

scala> ch3.checkpoint

scala> ch2.collect
res4: Array[String] = Array(1[1533633885066], 2[1533633885081])

scala> ch2.collect
res5: Array[String] = Array(1[1533633889716], 2[1533633889722])

scala> ch3.collect
res6: Array[String] = Array(1[1533633899554], 2[1533633899556])                 

scala> ch3.collect
res7: Array[String] = Array(1[1533633899808], 2[1533633899794])

scala> ch3.collect
res8: Array[String] = Array(1[1533633899808], 2[1533633899794])

scala> ch3.collect
res9: Array[String] = Array(1[1533633899808], 2[1533633899794])

查看HDFS上checkpoint的文件

[root@hadoop103 hadoop-2.8.2]# bin/hadoop fs -ls -R /checkpoint
drwxr-xr-x   - yinggu supergroup          0 2018-08-07 17:24 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c
drwxr-xr-x   - yinggu supergroup          0 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0
-rw-r--r--   3 yinggu supergroup        271 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0/part-00000
-rw-r--r--   3 yinggu supergroup        271 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0/part-00001
-rw-r--r--   3 yinggu supergroup        271 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0/part-00002
-rw-r--r--   3 yinggu supergroup        271 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0/part-00003
-rw-r--r--   3 yinggu supergroup        271 2018-08-07 17:23 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-0/part-00004
drwxr-xr-x   - yinggu supergroup          0 2018-08-07 17:25 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-4
-rw-r--r--   3 yinggu supergroup         23 2018-08-07 17:25 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-4/part-00000
-rw-r--r--   3 yinggu supergroup         23 2018-08-07 17:25 /checkpoint/ce68d190-9ed4-4bf4-93b1-656f6cb2a30c/rdd-4/part-00001

总结
(1)通过检查点机制能够把RDD的数据保存到一个非易失存储上,配合HDFS使用,
(2)检查点会切断RDD的血统关系。
(3)如果需要使用,则需要通过sparkcontext设置一个检查点目录: sc.setCheckpointDir("hdfs://master01:9000/checkpoint")
设置完成之后,行手动触发checkpoint进检查点的保存。
(4)检查点机制是懒执行的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值