Spark版本:spark-2.3.1

官方原文:https://spark.apache.org/docs/2.3.1/rdd-programming-guide.html

RDD持久性

Spark中最重要的功能之一是在整个操作中persisting(或caching)内存中的数据集。当持久化RDD时,每个节点都会存储它在内存中计算的所有分区,并在该数据集上的其他操作(或从中派生的数据集)中重用它们。这可以使未来的action更快(通常超过10倍)。缓存是迭代算法和快速交互式使用的关键工具。

您可以将RDD标记为使用其上的​​persist()​​或​​cache()​​方法持久化。第一次在action中计算时,它将保存在节点的内存中。Spark的缓存是容错的 - 如果RDD的任何分区丢失,它将自动使用最初创建它的转换重新计算。此外,每个持久RDD可以使用不同的​StorageLevel ​进行存储,例如,允许您将数据集保存在磁盘上,将其保存在内存中,但作为序列化的Java对象(以节省空间),将其复制到节点上。这些级别通过传递一个 ​​StorageLevel​​对象(​​Scala​​​, ​​Java​​​, ​​Python​​​)来设置​​persist()​​。该​​cache()​​方法是使用默认存储级别的简写,它是​​StorageLevel.MEMORY_ONLY​​(将反序列化对象存储在内存中)。完整的存储级别如下:

存储级别

含义

MEMORY_ONLY

将RDD作为反序列化的Java对象存储在JVM中。如果RDD不适合内存,则某些分区将不会被缓存,并会在每次需要时重新计算。这是默认级别。

MEMORY_AND_DISK

将RDD作为反序列化的Java对象存储在JVM中。如果RDD不适合内存,请存储不适合磁盘的分区,并在需要时从中读取它们。

MEMORY_ONLY_SER 

(Java和Scala)

将RDD存储为序列化的 Java对象(每个分区一个字节的数组)。与反序列化的对象相比,这通常更节省空间,特别是在使用 ​​快速序列化器时​​,但需要更多的CPU密集型读取。

MEMORY_AND_DISK_SER 

(Java和Scala)

与MEMORY_ONLY_SER类似,但将不适合内存的分区溢出到磁盘上,而不是每次需要时重新计算它们。

DISK_ONLY

将RDD分区仅存储在磁盘上。

MEMORY_ONLY_2,MEMORY_AND_DISK_2等

与上面的级别相同,但复制两个群集节点上的每个分区。

OFF_HEAP(实验)

与MEMORY_ONLY_SER类似,但将数据存储在 ​​堆内存储器中​​。这需要启用堆堆内存。

注意: 在Python中,存储的对象将始终与Pickle库串行化,所以选择序列化级别无关紧要。Python中的可用存储级别包括MEMORY_ONLYMEMORY_ONLY_2, MEMORY_AND_DISKMEMORY_AND_DISK_2DISK_ONLY,和DISK_ONLY_2​reduceByKey​​即使没有用户的呼叫,Spark也会在洗牌操作中自动保存一些中间数据(例如)​​persist​​。这是为了避免在洗牌过程中节点失败时重新计算整个输入。我们仍建议用户调用​​persist​​生成的RDD,如果他们打算重用它。

选择哪个存储级别?

Spark的存储级别旨在内存使用和CPU效率之间提供不同权衡。我们建议通过以下过程来选择一个:

  • 如果您的RDD适合默认存储级别(

​MEMORY_ONLY​

  • ),请将其留在那里。这是CPU处理效率最高的选项,允许RDD上的操作尽可能快地运行。
  • 如果没有,请尝试使用

​MEMORY_ONLY_SER​

  • 并​​选择快速序列化库,​​以使对象更加节省空间,但访问速度仍然相当快。(Java和Scala)
  • 除非计算数据集的函数很昂贵,否则它们会过滤大量数据,否则不要泄露到磁盘。否则,重新计算分区可能与从磁盘读取分区一样快。
  • 如果要快速恢复故障(例如,如果使用Spark来为Web应用程序提供请求),请使用复制的存储级别。所有的存储级别通过重新计算丢失的数据来提供完全的容错能力,但是复制的容量可让您继续在RDD上运行任务,而无需等待重新计算丢失的分区。

删除数据

Spark会自动监视每个节点上的高速缓存使用情况,并以最近最少使用(LRU)方式删除旧数据分区。如果您想要手动删除RDD,而不是等待它退出缓存,请使用该​​RDD.unpersist()​​方法。


以上是原文的翻译,以下是我提取出的关键信息,在实际使用RDD Persistence中有一定作用。

1、能够从分区的persist中受益的操作

  • cogroup()
  • groupWith(), groupByKey(), reduceByKey(),
  • join(), leftOuterJoin(), rightOuter Join()
  • combineByKey(), and lookup().

2、并非所有操作都需要persist

3、进行宽窄依赖划分时,需要对父RDD进行persist

4、复杂函数产生的RDD需要persist,节省时间


参考: