spark可以使用checkpoint来作为检查点,将rdd的数据写入hdfs文件,也可以利用本地缓存子系统。

当我们使用checkpoint将rdd保存到hdfs文件时,如果任务的临时文件长时间不删除,长此以往,hdfs会出现很多没有用的文件,spark也考虑到了这一点,因此,用了一些取巧的方式来解决这种问题。

spark config:

spark.cleaner.referenceTracking.cleanCheckpoints = 默认false

也就是说默认情况下,保存的文件一直都会放在dfs中,除非人工删除

下述内容均建立在值为true的情况下

设置检查点路径

spark.sparkContext().setCheckpointDir("hdfs://nameservice1/xx/xx");

存放到hdfs文件系统的好处是自带高容错性、可用性。

那么,所有运行的任务都写这个路径会不会出现覆盖的情况呢?答案是不会

  /**
* Set the directory under which RDDs are going to be checkpointed.
* @param directory path to the directory where checkpoint files will be stored
* (must be HDFS path if running in cluster)
*/
def setCheckpointDir(directory: String) { // If we are running on a cluster, log a warning if the directory is local.
// Otherwise, the driver may attempt to reconstruct the checkpointed RDD from
// its own local file system, which is incorrect because the checkpoint files
// are actually on the executor machines.
if (!isLocal && Utils.nonLocalPaths(directory).isEmpty) {
logWarning("Spark is not running in local mode, therefore the checkpoint directory " +
s"must not be on the local filesystem. Directory '$directory' " +
"appears to be on the local filesystem.")
} checkpointDir = Option(directory).map { dir =>
//利用uuid生成了一个子目录,存放的rdd文件将放到子目录中
val path = new Path(dir, UUID.randomUUID().toString)
val fs = path.getFileSystem(hadoopConfiguration)
fs.mkdirs(path)
fs.getFileStatus(path).getPath.toString
}
}

利用uuid的唯一性,使不同的进程间的checkpoint互不干扰,后续有checkpoint创建的请求时,将会在该目录下创建文件来保存rdd的内容

在生成checkpoint的ReliableRDDCheckpointData 方法中,

保存检查点

  /**
* Materialize this RDD and write its content to a reliable DFS.
* This is called immediately after the first action invoked on this RDD has completed.
*/
protected override def doCheckpoint(): CheckpointRDD[T] = {
//写入到可靠的文件中
val newRDD = ReliableCheckpointRDD.writeRDDToCheckpointDirectory(rdd, cpDir) // Optionally clean our checkpoint files if the reference is out of scope
//默认false,才会注册清理器
if (rdd.conf.get(CLEANER_REFERENCE_TRACKING_CLEAN_CHECKPOINTS)) {
rdd.context.cleaner.foreach { cleaner =>
//注册清理事件
cleaner.registerRDDCheckpointDataForCleanup(newRDD, rdd.id)
}
} logInfo(s"Done checkpointing RDD ${rdd.id} to $cpDir, new parent is RDD ${newRDD.id}")
newRDD
}

注册事件

注册清理事件的意义是当rdd对象无其他引用依赖时,由清理线程异步清理对应的checkpoint文件

  /** Register a RDDCheckpointData for cleanup when it is garbage collected. */
def registerRDDCheckpointDataForCleanup[T](rdd: RDD[_], parentId: Int): Unit = {
registerForCleanup(rdd, CleanCheckpoint(parentId))
} /** Register an object for cleanup. */
private def registerForCleanup(objectForCleanup: AnyRef, task: CleanupTask): Unit = {
referenceBuffer.add(new CleanupTaskWeakReference(task, objectForCleanup, referenceQueue))
}

referenceBuffer的作用是持有CleanupTaskWeakReference对象的引用,防止CleanupTaskWeakReference被提前回收,导致提前清理。

弱引用对象

CleanupTaskWeakReference继承自WeakReference,将referent(也就是rdd),绑定到referenceQueue上,如果gc回收时,发现referent除了referenceQueue这个弱引用外,已经没有其他对象引用,就会将CleanupTaskWeakReference对应放入referenceQueue中

//引用队列,当garbage collector发现对应的可达性改变被发现时,会将引用对象推入队列中
//这是通过Reference.enqueue方法实现的 public boolean enqueue() {return this.queue.enqueue(this);}
private val referenceQueue = new ReferenceQueue[AnyRef] /**
* A WeakReference associated with a CleanupTask.
*
* When the referent object becomes only weakly reachable, the corresponding
* CleanupTaskWeakReference is automatically added to the given reference queue.
*/
private class CleanupTaskWeakReference(
val task: CleanupTask,
referent: AnyRef,
referenceQueue: ReferenceQueue[AnyRef])
extends WeakReference(referent, referenceQueue)

回收线程

再来细致的讲回收线程

在SparkContext初始化时,会启动cleaner,代码较多,直接依次

_cleaner =
if (_conf.get(CLEANER_REFERENCE_TRACKING)) {
Some(new ContextCleaner(this))
} else {
None
}
_cleaner.foreach(_.start())

  /** Start the cleaner. */
def start(): Unit = {
cleaningThread.setDaemon(true) //守护进程
cleaningThread.setName("Spark Context Cleaner")
cleaningThread.start()
//这里有点银弹的意思,定时执行gc,默认半小时一次,主要是应对长时间任务问题
periodicGCService.scheduleAtFixedRate(() => System.gc(),
periodicGCInterval, periodicGCInterval, TimeUnit.SECONDS)
} private val cleaningThread = new Thread() { override def run() { keepCleaning() }}

  /** Keep cleaning RDD, shuffle, and broadcast state. */
private def keepCleaning(): Unit = Utils.tryOrStopSparkContext(sc) {
while (!stopped) {
try {
//从referenceQueue中取可以回收的弱引用对象,弱引用对象返回表示登记的rdd已经可回收了
val reference = Option(referenceQueue.remove(ContextCleaner.REF_QUEUE_POLL_TIMEOUT))
.map(_.asInstanceOf[CleanupTaskWeakReference])
// Synchronize here to avoid being interrupted on stop()
synchronized {
reference.foreach { ref =>
logDebug("Got cleaning task " + ref.task)
//清除强引用
referenceBuffer.remove(ref)
ref.task match {
case CleanRDD(rddId) =>
doCleanupRDD(rddId, blocking = blockOnCleanupTasks)
case CleanShuffle(shuffleId) =>
doCleanupShuffle(shuffleId, blocking = blockOnShuffleCleanupTasks)
case CleanBroadcast(broadcastId) =>
doCleanupBroadcast(broadcastId, blocking = blockOnCleanupTasks)
case CleanAccum(accId) =>
doCleanupAccum(accId, blocking = blockOnCleanupTasks)
case CleanCheckpoint(rddId) =>
doCleanCheckpoint(rddId) //如果任务是cleancheckpoint任务
}
}
}
} catch {
case ie: InterruptedException if stopped => // ignore
case e: Exception => logError("Error in cleaning thread", e)
}
}
}

  /**
* Clean up checkpoint files written to a reliable storage.
* Locally checkpointed files are cleaned up separately through RDD cleanups.
*/
def doCleanCheckpoint(rddId: Int): Unit = {
try {
logDebug("Cleaning rdd checkpoint data " + rddId)
//删除checkpoint操作被触发
ReliableRDDCheckpointData.cleanCheckpoint(sc, rddId)
listeners.asScala.foreach(_.checkpointCleaned(rddId))
logInfo("Cleaned rdd checkpoint data " + rddId)
}
catch {
case e: Exception => logError("Error cleaning rdd checkpoint data " + rddId, e)
}
}

特殊操作的意思

为什么要定时执行System.gc()去触发full gc?

  • 由于删除rdd checkpoint的方法利用了WeakReference,它是一个严重依赖gc的功能,如果没有gc,就不会发现对象可回收,也就不会触发回收逻辑。
  • 极端情况可能出现长时间只有yong gc,而老年区的对象长时间无法回收,而对象早已无其他引用,利用System.gc()来尝试执行full gc,达到回收老年代的目的

总结

  • 默认情况下,保存的文件一直都会放在dfs中,除非人工删除
  • 及时开启spark.cleaner.referenceTracking.cleanCheckpoints,也不能意味着一定能回收,因为垃圾回收并非一定会在合适的时间执行,有可能最终也没有触发弱引用清理任务逻辑

Spark如何删除无效rdd checkpoint的更多相关文章

  1. 大数据入门第二十二天——spark(二)RDD算子(2)与spark其它特性

    一.JdbcRDD与关系型数据库交互 虽然略显鸡肋,但这里还是记录一下(点开JdbcRDD可以看到限制比较死,基本是鸡肋.但好在我们可以通过自定义的JdbcRDD来帮助我们完成与关系型数据库的交互.这 ...

  2. Spark性能调优-RDD算子调优篇(深度好文,面试常问,建议收藏)

    RDD算子调优 不废话,直接进入正题! 1. RDD复用 在对RDD进行算子时,要避免相同的算子和计算逻辑之下对RDD进行重复的计算,如下图所示: 对上图中的RDD计算架构进行修改,得到如下图所示的优 ...

  3. Spark源码分析之Checkpoint的过程

    概述 checkpoint 的机制保证了需要访问重复数据的应用 Spark 的DAG执行图可能很庞大,task 中计算链可能会很长,这时如果 task 中途运行出错,那么 task 的整个需要重算非常 ...

  4. spark第一篇:RDD Programming Guide

    预览 在高层次上,每一个Spark应用(application)都包含一个驱动程序(driver program),该程序运行用户的主函数(main function),并在集群上执行各种并行操作. ...

  5. Spark操作算子本质-RDD的容错

    Spark操作算子本质-RDD的容错spark模式1.standalone master 资源调度 worker2.yarn resourcemanager 资源调度 nodemanager在一个集群 ...

  6. Spark 并行计算模型:RDD

    Spark 允许用户为driver(或主节点)编写运行在计算集群上,并行处理数据的程序.在Spark中,它使用RDDs代表大型的数据集,RDDs是一组不可变的分布式的对象的集合,存储在executor ...

  7. Spark Streaming揭秘 Day8 RDD生命周期研究

    Spark Streaming揭秘 Day8 RDD生命周期研究 今天让我们进一步深入SparkStreaming中RDD的运行机制.从完整的生命周期角度来说,有三个问题是需要解决的: RDD到底是怎 ...

  8. word中几个好用的宏代码(立方米上标、关闭样式自动更新、删除无效样式、表格加粗边框、宋体引号)

    Sub 替换立方米() With Selection.Find .Text = "m3" .Replacement.Text = "mm3" .Forward ...

  9. 【原创】大数据基础之Spark(4)RDD原理及代码解析

    一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-di ...

随机推荐

  1. 5.CyclicBarrier-栅栏

  2. pytest自学第二期

    2.1 通过python解释器调用 pytest 我不知道有什么用:-) 以后就这样,如果有自己学过但是不知道的东西,就挂在那里晒着鞭尸,一直不会就一直鞭尸,直到自己参透了其中的道理再回到这里补全 在 ...

  3. [GXYCTF2019]禁止套娃 1 &无参数RCE

    [GXYCTF2019]禁止套娃 1 啥都没有那只能上扫描器来一探究竟了. 扫完没有啥结果,但网上找了一下说是git泄露,但是我这里显示了403. <?php include "fla ...

  4. MySQL中的find_in_set()函数使用技巧心得与应用场景总结

    Author:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,CSDN官方首发原创文章 企业博客 CSDN.com 个人博 ...

  5. 微服务电商项目发布重大更新,打造Spring Cloud最佳实践!

    Spring Cloud实战电商项目mall-swarm地址:转发+关注 私信我获取地址 系统架构图   系统架构图 项目组织结构 mall├── mall-common-- 工具类及通用代码模块├─ ...

  6. vue项目中视频播放结束返回首页出现1秒左右的白屏问题

    vue项目的性能优化问题,一直以来都是大家比较关注的. 近日负责的项目中,使用了SignalR实时通讯,客户端中点击发起播放视频的请求到服务器,服务器接到请求后再调用前端的播放视频方法,以此来达到播放 ...

  7. spring+springmvc+mybatis+shiro

    创建maven框架https://blog.csdn.net/Ajax_mt/article/details/78549119 具体下边 https://blog.csdn.net/w2222288/ ...

  8. 随机梯度下降法(Stochastic gradient descent, SGD)

    BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的样本(样本量小)    Mold 一直在更新 SGD(Stochastic gradientdescent)随机 ...

  9. 插头 dp

    插头dp 洛谷 黑题板子? P5056 给出n×m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路.问有多少种铺法? 1.轮廓线 简单地说,轮廓线就是已决策格子和未决策格子的分界线: 2,插 ...

  10. HTML CSS+JS想要做放大镜练习,如何获取同样的大图和小图?

    1.进入某商城找到对应的图片: 步骤一: 步骤二: 步骤三: 2.检查源代码: 情况一:按F12 情况二:鼠标在网页内,直接右键-->"检查元素" 1.选中选择部分 2.点击 ...