基于本文回答
0
评论

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() 手动释放资源。

右滑查看面试常问