一个RDD如果被多次操作,为了提交后续的执行效率,我们建议对该RDD进行持久化操作。
如何对一个RDD进行持久化呢?
rdd.persist()/cache()就完成了rdd的持久化操作,我们可以将该rdd的数据持久化到内存,磁盘,等等。
同样,如果我们已经不再对该rdd进行一个操作,而此时程序并没有终止,我们便可以卸载已经持久化的该rdd数据,rdd.unPersist()。
持久化策略
MEMORY_ONLY(默认) | rdd中的数据以java对象的形式,保存在内存中,运算效率是这几种中最高的,但是也是最占内存的,而且因为以java对象的形式存在,所以很容易引起频繁的GC(gc和java对象的数量成正比),如果内存不能够存储下所有的数据,就将那一部分数据不进行持久化。 |
MEMORY_ONLY_SER | 和MEMEORY_ONLY一模一样,多增加了一点,数据是以序列化的方式存在的。一个partition就是一个字节数组,就是一个java对象。 |
MEMORY_AND_DISK | 在MEMOERY_ONLY的基础之上,将那部分无法再内存持久化的数据,持久化到磁盘。 |
MEMORY_AND_DISK_SER | 在MEMEORY_ONLY_SER的基础之上,将那部分无法再内存持久化的数据,持久化到磁盘。 |
DISK_ONLY | 不用内存,直接以未经序列化的格式保存到磁盘 |
DISK_ONLY_SER | DISK_ONLY的基础之上进行了序列化。 |
xxx_2 | 以上所有操作的基础之上进行备份。 |
OFF_HEAP | 使用堆外内存。Tachyon(alluxio 内存版的hdfs) |
选择何种持久化策略
第一步:如果要持久化的数据是可以在内存中进行保存,那么毫无疑问,选择MEMEORY_ONLY,因为这种方式的效率是最高的,但是在生成中往往要进行缓存的数据量还是蛮大的,而且因为数据都是未经序列化的java对象,所以很容易引起频繁的gc。
第二步:如果上述满足不了,就退而求其次,MEMORY_ONLY_SER,这种方式增加的额外的性能开销就是序列化和反序列化,经过反序列化之后的对象就是纯java对象,因此性能还是蛮高的。
第三步:如果还是扛不住,再退而求其次,MEMOEY_AND_DISK_SER,因为到这一步的话,那说明对象体积确实很多,为了提交执行效率,应该尽可能的将数据保存在内存,所以就对数据进行序列化,其次在序列化到磁盘。
一般情况下DISK_ONLY,DISK_SER不用,效率太低,有时候真的不容从源头计算一遍。
一般情况下我们都不用XXX_2,代备份的种种持久化策略,除非程序对数据的安全性要求非常高,或者说备份的对性能的消耗低于从头再算一遍,我们可以使用这种xxx_2以外,基本不用。