精选·Spark

cache/persist 和 checkpoint 有什么区别?分别什么时候用?

91学AI·2026/7/13·8 阅读

考察点

这题看似简单,但能说清「血缘是否切断」这个本质区别的人不多。面试官想听:两者在存储位置、血缘处理、失败恢复行为上的对比;checkpoint 为什么是 action 而 cache 是 lazy 的;迭代计算里为什么要两者配合使用;以及 StorageLevel 的选择逻辑。追问常往「cache 会不会丢数据」「checkpoint 目录管理」「persist 的副本级别」方向走。

参考答案

一句话对比

cache/persist 是性能优化:把计算结果留在内存或磁盘,下次用不用再算,但血缘还在,数据丢了按血缘重算。checkpoint 是容错保障:把结果写到可靠外部存储(HDFS),切断血缘,从此这个 RDD 相当于数据源,前面的链路全扔掉。

逐维度对比

维度cache / persistcheckpoint
目的复用提速长链容错
存储executor 内存/本地磁盘HDFS 等可靠存储
血缘保留切断
丢失后按血缘重算(可跳缓存祖先)从 checkpoint 文件读回
执行时机lazy,action 触发eager,本身是 action
可靠性单副本默认,executor 挂即丢依赖 HDFS 副本,高可靠

cache/persist 的细节

cache() 就是 persist(MEMORY_ONLY) 的简写。StorageLevel 的选择是内存和可靠性的权衡:

  • MEMORY_ONLY:默认。内存放得下就快,放不下的分区下次用时重算。
  • MEMORY_AND_DISK:最实用的级别。内存放不下的部分 spill 到 executor 本地磁盘,重算降级为读盘,性能损失可控。
  • MEMORY_ONLY_SER / MEMORY_AND_DISK_SER:序列化存储,省内存(Java 对象头开销大,序列化后体积可能小一半以上)费 CPU(每次用要反序列化)。大缓存、内存紧张时用。
  • *_2 副本级别:两份副本,executor 挂了一个还有另一个。生产上很少用,因为重算通常比维护副本便宜——副本级别是血淋淋的教训换来的经验,不是常规配置。

cache 是 lazy 的,标记后第一个 action 才真正物化。用完要 unpersist() 释放,否则 storage 内存被占着。

checkpoint 的细节

checkpoint 解决的是血缘过长的问题。迭代计算(机器学习梯度下降、图算法 PageRank)里 RDD 链滚到几十上百代,driver 端血缘元数据膨胀,任一 partition 丢失都要回溯重算全链,代价不可接受。checkpoint 把当前 RDD 物化到 HDFS,把它的血缘替换成一个指向 checkpoint 文件的引用,从此重算只回溯到这里。

两个关键用法细节:

sc.setCheckpointDir("hdfs:///checkpoints/xxx")  // 必须先设目录
rdd.cache()          // 先 cache!
rdd.checkpoint()     // 再 checkpoint
rdd.count()          // 触发:第一次算走 cache,checkpoint 直接读缓存写盘

不 cache 直接 checkpoint,这个 RDD 会被算两遍——第一遍是 checkpoint 自己的物化,第二遍是后续 action 用的时候。cache 之后 checkpoint 直接从内存写盘,只算一遍。这是 checkpoint 最容易踩的坑。

checkpoint 是 action(立即执行),且目录需要用户管理——job 结束后 checkpoint 文件不会自动清理,长期跑的任务要规划目录生命周期。

什么时候用哪个

判断逻辑很简单:

  • 一个 RDD/DataFrame 会被多个下游分支用到(比如一张中间结果表 join 多个维度),cache。
  • 血缘太长(迭代、复杂 ETL 多步链),担心重算代价或 driver 元数据膨胀,在关键节点 checkpoint。
  • 两者都要:先 cache 再 checkpoint,既提速又保容错。

反面教材也常见:什么都 cache,结果 storage 内存被挤爆,execution 区域 spill 到飞起,整体反而变慢。cache 是有成本的,只缓存确实复用重算代价高的数据。

一个容易混淆的点

cache 之后如果 executor 挂了,缓存的分区丢失,Spark 会按血缘重算——cache 不是容错机制,只是性能优化。所以「cache 了就不会重算」是错的,「cache 了就算 executor 挂也能恢复」也是错的(会重算,只是能命中缓存的部分跳过)。真正的容错只有两条路:血缘重算、checkpoint 读回。

可能的追问

  • checkpoint 和 cache 后重启 job,数据还在吗? checkpoint 在 HDFS,job 重启后可以从 checkpoint 文件恢复(新 job 里要重新建立指向 checkpoint 的 RDD);cache 在 executor 内存/本地盘,job 结束全部释放,不存在跨 job 复用。
  • DataFrame 也有 checkpoint 吗? 有,df.checkpoint()(Spark 2.1+,需要 setCheckpointDir)。语义相同:切断血缘、物化到可靠存储。但 DataFrame 的 cache 比 RDD 更常见,因为 Catalyst 优化后重算代价相对低。
  • persist 之后 unpersist 的时机怎么把握? 最后一个使用这个 RDD 的 action 之后立刻 unpersist。Streaming 场景里是每批次处理完 unpersist 上一批次的缓存。漏了 unpersist 是生产环境内存泄漏(storage 区域膨胀)的常见原因。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.