(四)Spark学习笔记之缓存持久化

缓存实战

缓存和持久化是 RDD 计算过程中的一种调优技术。缓存和持久化可以保存中间计算结果,以便在后续的 stage 重用总使用,而不需要再次从头计算。这些中间结果以 RDD 的形式保存在内存中,或者磁盘中。

StorageLevel 描述了 RDD 是如何被持久化的,可以提供:

  • RDD 持久化磁盘还是内存存储;
  • RDD 持久化手使用了off-leap;
  • RDD 是否需要被序列化;

StorageLevel 的属性包括:

  • NONE : 默认
  • DISK_ONLY:RDD 只是存储在磁盘,内存消耗低,CPU 密集型。
  • DISK_ONLY_2:
  • MEMORY_ONLY:RDD 以非序列化的 Java 对象存储在 JVM 中。如果 RDD 的大小超过了内存大小,那么某些 partition 将不会缓存,下次使用时需要重新计算。这种存储级别比较消耗内存,但是不耗 CPU。数据只是存储在内存而不是磁盘。
  • MEMORY_ONLY_2:
  • MEMORY_ONLY_SER:RDD 以序列化 Java 对象(每个partition一个字节数组)的形式存储。在这个级别,内存空间使用很低,CPU 计算时间高。(提高内存存储)
  • MEMORY_ONLY_SER_2:
  • MEMORY_AND_DISK:RDD 以非序列化的 Java 对象存储在 JVM 中,当 RDD 的大小超过了内存大小,多出来的 partition 将会缓存在磁盘中,后续计算如果用到这些多出来的 partition,会从磁盘上获取。这种存储级别比较耗内存,CPU 消耗一般。该存储同时利用了内存和磁盘两方面。
  • MEMORY_AND_DISK_2:
  • MEMORY_AND_DISK_SER:与 MEMORY_ONLY_SER 类似,只是将大于内存的 partition 数据序列化到磁盘,而不是重新计算。内存消耗低,CPU 消耗高。
  • MEMORY_AND_DISK_SER_2:

案例:

val lines = sc.textFile("README.md")
scala> lines.getStorageLevel
res0: org.apache.spark.storage.StorageLevel = StorageLevel(disk=false, memory=false, offheap=false, deserialized=false, replication=1)

RDD 可以被缓存 cache,使用 cache() 方法,也可以被持久化 persist,使用 persist() 方法。

cache() 和 persist() 方法的区别在于:cache() 等价于 persist(MEMORY_ONLY),即 cache() 方法仅仅是 persist() 使用默认存储级别 MEMORY_ONLY 的一种情况。使用 persist() 方法可以设置不同的 storageLevel。

对于迭代算法,缓存和持久化是一个重要的工具。因为,在一个节点上缓存了 RDD 的某个 partition 到内存中,其就可以在下面的计算中重复使用,而不需要从头计算,可以使计算性能提高 10 倍。如果缓存中的某个 partition 丢失或者不可用,根据 SparkRDD 的容错特性,Spark 会从头计算这个 partition。

什么时候需要对 RDD 进行持久化,在 spark 计算中,多次使用同一个 RDD,如:使用 RDD 计算 count()、max()、min() 等 action 操作。而且这些操作可能会很耗内存,尤其是迭代算法(机器学习)。为了解决频繁重复计算的问题,此时就需要对 RDD 进行持久化。

spark自动监控每个节点的缓存,并以 LRU(最近最少使用)算法删除旧数据分区。LRU 算法保证了最常用的数据被缓存。并且可以使用 RDD.unpersist() 来手动删除缓存。

spark 会在 shuffle 操作中自动持久化一些中间数据(reduceByKey),即没有调用 persist 方法。这样做是为了避免在 shuffle 期间节点故障时重新计算整个输入。如果用户准备重用生成的 RDD,推荐显式调用持久化。

项目中如何选择存储级别

spark 的存储级别是为了在内存使用和 CPU 效率之间不同的权衡,具体选择哪个存储级别,可以从以下方面考虑:

  • 如果 RDDs 数据适合默认存储级别(MEMORY_ONLY),那么就是用默认存储级别。此时,RDD 的运算速度最快。
  • 如果没有,可以尝试使用 MEMORY_ONLY_SER 并选择一个快速序列化库,以便使对象更节省空间,但访问速度仍然相当快。
  • 不要持久化到磁盘,除非计算数据集的函数很耗时,或者过滤了大量数据。因为,从磁盘读取分区,可能没有重新计算分区块。
  • 如果需要快速故障恢复,则使用副本存储级别。

猜你喜欢

转载自blog.csdn.net/dec_sun/article/details/89389876