Spark中cache和persist的作用以及存储级别
前言
Spark开发高性能的大数据计算作业并不是那么简单。如果没有对Spark作业进行合理的调优,Spark作业的执行速度可能会很慢,这样就完全体现不出Spark作为一种快速大数据计算引擎的优势来。因此,想要用好Spark,就必须对其进行合理的性能优化。
有一些代码开发基本的原则,避免创建重复的RDD,尽可能复用同一个RDD,如下,我们可以直接用一个RDD进行多种操作。
val rdd1 = sc.textFile("xxx")
rdd1.xxxxx.xxxx.collect
rdd1.xxx.xxcollect
但是Spark中对于一个RDD执行多次算子的默认原理是这样的:每次你对一个RDD执行一个算子操作时,都会重新从源头处计算一遍,计算出那个RDD来,然后再对这个RDD执行你的算子操作。对于上面的代码,sc.textFile("xxx")
会执行两次,这种方式的性能是很差的。
因此对于这种情况,我的建议是:对多次使用的RDD进行持久化。此时Spark就会根据你的持久化策略,将RDD中的数据保存到内存或者磁盘中。以后每次对这个RDD进行算子操作时,都会直接从内存或磁盘中提取持久化的RDD数据,然后执行算子,而不会从源头处重新计算一遍这个RDD,再执行算子操作。
持久化
如果要对一个RDD进行持久化,只要对这个RDD调用cache()
和persist()
即可。
val rdd1 = sc.textFile("xxx").cache
rdd1.xxxxx.xxxx.collect
rdd1.xxx.xxcollect
cache()
方法表示:使用非序列化的方式将RDD中的数据全部尝试持久化到内存中。- 此时再对rdd1执行两次算子操作时,只有在第一次算子时,才会将这个rdd1从源头处计算一次。第二次执行算子时,就会直接从内存中提取数据进行计算,不会重复计算一个rdd。
def cache(): this.type = persist()
persist()
方法表示:手动选择持久化级别,并使用指定的方式进行持久化。def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)
- 默认缓存级别是
StorageLevel.MEMORY_ONLY
,也就是cache就是这个默认级别的
RDD的缓存级别
持久化级别 | 含义解释 |
---|---|
MEMORY_ONLY | 使用未序列化的Java对象格式,将数据保存在内存中。如果内存不够存放所有的数据,则数据可能就不会进行持久化。那么下次对这个RDD执行算子操作时,那些没有被持久化的数据,需要从源头处重新计算一遍。这是默认的持久化策略,使用cache()方法时,实际就是使用的这种持久化策略。 |
MEMORY_AND_DISK | 使用未序列化的Java对象格式,优先尝试将数据保存在内存中。如果内存不够存放所有的数据,会将数据写入磁盘文件中,下次对这个RDD执行算子时,持久化在磁盘文件中的数据会被读取出来使用。 |
MEMORY_ONLY_SER | 基本含义同MEMORY_ONLY。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。 |
MEMORY_AND_DISK_SER | 基本含义同MEMORY_AND_DISK。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。 |
DISK_ONLY | 使用未序列化的Java对象格式,将数据全部写入磁盘文件中。 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等 | 对于上述任意一种持久化策略,如果加上后缀_2,代表的是将每个持久化的 |