Spark cache() 和 persist() 的区别是什么?
在 Apache Spark 中,cache() 和 persist() 都是用于将 RDD、DataFrame 或 Dataset 的中间结果保存起来(持久化),以便在后续的 Action 操作中重复使用,从而避免重复计算。
它们的主要区别在于 灵活性 和 默认存储级别。
简单来说:cache() 是 persist() 的一个特例(快捷方式)。
以下是详细的对比:
1. 核心区别
| 特性 | cache() | persist() |
|---|---|---|
| 定义 | 是 persist() 的简化版,不接受参数。 |
是通用的持久化方法,可以接受 StorageLevel 参数。 |
| 灵活性 | 低。只能使用默认的存储级别。 | 高。可以自定义存储级别(内存、磁盘、序列化、副本等)。 |
| 底层实现 | 内部直接调用了 persist()。 |
它是实现持久化逻辑的基础方法。 |
2. 默认存储级别 (Storage Level) 的差异
这是面试中最大的考点,因为 RDD 和 DataFrame 的默认行为不同:
对于 RDD:
cache()的默认级别是MEMORY_ONLY(仅内存,反序列化对象)。- 这意味着如果内存不够,数据就会丢失,下次需要重新计算。
对于 DataFrame / Dataset:
cache()的默认级别是MEMORY_AND_DISK。- 这意味着如果内存不够,溢出的数据会自动写入磁盘,不会丢失。
对于
persist():- 你需要手动指定级别,例如
persist(StorageLevel.DISK_ONLY)。 - 如果不传参数调用
persist(),它的行为等同于cache()。
- 你需要手动指定级别,例如
3. persist() 支持的存储级别 (StorageLevel)
通过 persist(),你可以精细控制数据的存储方式:
- MEMORY_ONLY: 仅保存在内存中(Java 对象)。速度最快,但消耗内存大。
- MEMORY_AND_DISK: 优先内存,内存不足存磁盘。
- DISK_ONLY: 仅存磁盘。
- MEMORY_ONLY_SER: 仅保存在内存中,但以序列化(字节流)形式存储。比对象方式节省空间,但读取时需要 CPU 进行反序列化(空间换时间)。
- MEMORY_AND_DISK_SER: 同上,内存不足存磁盘。
- OFF_HEAP: 使用堆外内存(Tachyon/Alluxio 等)。
- _2 (后缀): 例如
MEMORY_ONLY_2,表示将数据复制一份副本到集群的另一个节点上(用于高可用容错)。
4. 代码示例 (Scala)
plaintext
import org.apache.spark.storage.StorageLevel
val rdd = sc.parallelize(1 to 1000)
// 1. 使用 cache()
// 对于 RDD,这等同于 persist(StorageLevel.MEMORY_ONLY)
rdd.cache()
// 2. 使用 persist() 自定义
// 仅存储在磁盘,不占用内存
rdd.persist(StorageLevel.DISK_ONLY)
// 3. 使用序列化存储以节省内存
rdd.persist(StorageLevel.MEMORY_ONLY_SER)
总结
- 如果你只是想快速地将数据暂存,且不在乎(或者不确定)具体的存储介质,直接用
cache()。 - 如果你的内存非常紧张,需要强制数据存入磁盘,或者需要使用序列化来压缩数据体积,或者需要数据高可用(副本),则必须使用
persist(StorageLevel...)。
注意: 无论是 cache 还是 persist,它们都是 Lazy(懒执行) 的。只有当第一次触发 Action(如 count(), collect(), show())时,数据才会被真正计算并缓存。使用完后,建议调用 unpersist() 手动释放资源。
右滑查看面试常问