Spark RDD等中cache()和persist()区别及持久化级别、策略选择

@Author  : Spinach | GHB
@Link    : http://blog.csdn.net/bocai8058


前言

在Spark开发过程中,会遇到对同一个RDD多次使用或多次想再其基础上执行不同的算子的情况,而Spark默认的执行原理是:每次对一个RDD执行一个算子操作时,都会重新从源头计算一遍,计算出那个RDD来,然后再对这个RDD执行你的算子操作。而这种方式造成了不同程度的计算资源浪费、执行性能差。

因此针对这种情况,建议:对多次使用的RDD进行持久化操作

Spark会根据你的持久化策略,将RDD中的数据保存到内存或磁盘中。持久化后的执行原理是:每次对一个RDD执行一个算子操作时,都会直接从内存或磁盘中提取持久化的RD数据,然后再其基础上执行你的算子操作,而不会从源头重新计算一遍这个RDD,从而提高了执行效率。

cache()

将数据持久化到内存或磁盘中。DataSet的cache默认缓存级别,是 MEMORY_AND_DISK;而 RDD的cache默认缓存级别,是MEMORY_ONLY。

  • cache()
    DataSet中是使用未序列化的Java对象格式,优先尝试将数据持久化在内存中。如果内存不够存放所有的数据,会将数据写入磁盘文件中。
    在这里插入图片描述
    RDD中是使用未序列化的Java对象格式,将数据保存在内存中。
    在这里插入图片描述

persist()

可根据持久化策略将数据持久化,其中持久化策略有:MEMORY_ONLY,MEMORY_AND_DISK,MEMORY_ONLY_SER,MEMORY_AND_DISK_SER,DISK_ONLY,MEMORY_ONLY_2,MEMORY_AND_DISK_2,etc。而默认持久化策略为MEMORY_AND_DISK,等同于cache()。

  • persist() 针对于DataSet默认缓存级别是 MEMORY_AND_DISK,而针对于RDD默认缓存级别是MEMORY_ONLY,等同于不同集合下的cache()。
  • persist( StorageLevel.xxxxxx ) 可根据持久化策略将数据持久化,具体持久化策略详解见下一节
    在这里插入图片描述

persist()的持久化级别和策略选择

  1. 持久化级别

对于persist()方法而言,可以根据不同的业务场景选择不同的持久化级别,具体持久化级别介绍如下:

持久化级别含义解释优缺点
MEMORY_ONLY使用未序列化的Java对象格式,将数据保存在内存中。如果内存不够存放所有的数据,则数据可能就不会进行持久化。
MEMORY_AND_DISK使用未序列化的Java对象格式,优先尝试将数据保存在内存中。如果内存不够存放所有的数据,会将数据写入磁盘文件中。使用了未序列的Java对象格式,可能会造成内存和磁盘空间开销过大。
MEMORY_ONLY_SER基本含义同MEMORY_ONLY。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。
MEMORY_AND_DISK_SER基本含义同MEMORY_AND_DISK。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。
DISK_ONLY使用未序列化的Java对象格式,将数据全部写入磁盘文件中。使用了未序列的Java对象格式,造成磁盘空间开销过大,并且采用此方式,数据读写磁盘的速度相比内存慢。
MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等.对于上述任意一种持久化策略,如果加上后缀_2,代表的是将每个持久化的数据,都复制一份副本,并将副本保存到其他节点上。这种基于副本的持久化机制主要用于进行容错。假如某个节点挂掉,节点的内存或磁盘中的持久化数据丢失了,那么后续对RDD计算时还可以使用该数据在其他节点上的副本。如果没有副本的话,就只能将这些数据从源头处重新计算一遍了。同样数据复制以及网络传输会导致较大的性能开销
  1. 策略选择
  • 默认情况下,性能最高的当然是MEMORY_ONLY,但前提是你的内存必须足够足够大,可以绰绰有余地存放下整个RDD的所有数据。因为不进行序列化与反序列化操作,就避免了这部分的性能开销;对这个RDD的后续算子操作,都是基于纯内存中的数据的操作,不需要从磁盘文件中读取数据,性能也很高;而且不需要复制一份数据副本,并远程传送到其他节点上。但是这里必须要注意的是,在实际的生产环境中,恐怕能够直接用这种策略的场景还是有限的,如果RDD中数据比较多时(比如几十亿),直接用这种持久化级别,会导致JVM的OOM内存溢出异常。

  • 如果使用MEMORY_ONLY级别时发生了内存溢出,那么建议尝试使用MEMORY_ONLY_SER级别。该级别会将RDD数据序列化后再保存在内存中,此时每个partition仅仅是一个字节数组而已,大大减少了对象数量,并降低了内存占用。这种级别比MEMORY_ONLY多出来的性能开销,主要就是序列化与反序列化的开销。但是后续算子可以基于纯内存进行操作,因此性能总体还是比较高的。此外,可能发生的问题同上,如果RDD中的数据量过多的话,还是可能会导致OOM内存溢出的异常。

  • 如果纯内存的级别都无法使用,那么建议使用MEMORY_AND_DISK_SER策略,而不是MEMORY_AND_DISK策略。因为既然到了这一步,就说明RDD的数据量很大,内存无法完全放下。序列化后的数据比较少,可以节省内存和磁盘的空间开销。同时该策略会优先尽量尝试将数据缓存在内存中,内存缓存不下才会写入磁盘。

  • 通常不建议使用DISK_ONLY和后缀为_2的级别:因为完全基于磁盘文件进行数据的读写,会导致性能急剧降低,有时还不如重新计算一次所有RDD。后缀为_2的级别,必须将所有数据都复制一份副本,并发送到其他节点上,数据复制以及网络传输会导致较大的性能开销,除非是要求作业的高可用性,否则不建议使用。


引用:https://blog.csdn.net/u012102306/article/details/51322209 | http://spark.apache.org/docs/2.3.3/api/scala/index.html#org.apache.spark.sql.Dataset

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值