1. 为什么RDD需要持久化?
RDD持久化解决的问题:
每当Action操作执行,其之前的Transformation才会被触发,形成RDD链条。Action操作完成后,该RDD会被丢弃。当再次执行该Action操作后,又会重新读取文件填充,在大数据量的情况下,形成过程和Action操作都非常耗时,整个Spark应用性能大大降低。
通过将RDD中的所有数据持久化到所在节点的内存中(缓存思想)以实现“一次读取,一次形成,多次复用,直接取出”。从而在很多场景下,可以大幅度提升Spark应用程序的性能。据官方文档,甚至可以提高十倍。
2. 节点如何持久化?
当RDD进行持久化操作时,每个节点都会将自己操作的RDD的partition持久化到本地内存中,并且之后在RDD的反复使用中,直接使用内存中缓存的partition。Spark自身会在Shuffle操作时进行数据的持久化,比如写入磁盘,主要是为了在节点操作失败时,避免重新计算整个过程。
3. 如何操作持久化?
只需要调用被持久化的RDD的cache()/persist()即可。在RDD第一次被计算出来时,就会直接缓存在每个节点。且Spark持久化机制自动容错,若持久化的RDD的任何partition丢失,则会自动根据来源RDD,进行Transformation重演形成该partition。
cache()与persist()的区别在于: cache()是persist()的一种简化方式,其底层调用persist(MEMORY_ONLY),将数据持久化到内存中。如果需要从内存中清楚缓存,可以使用unpersist()。
4. Demo
public static void main(String[] args) {
SparkConf conf = new SparkConf().setAppName("persist" ).setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf );
JavaRDD<String> javaRDD = sc.textFile("C:\\Users\\Z-Jay\\Desktop\\spark.txt" ).cache();
//第一次操作 无cache 317 有cache 383
long beginTime = System .currentTimeMillis();
long count = javaRDD.count();
long endTime = System .currentTimeMillis();
System.out.println( "Time:"+(endTime -beginTime ));
//第二次操作 无cache 26 有 cache 26
beginTime = System. currentTimeMillis();
count = javaRDD .count();
endTime = System. currentTimeMillis();
System.out.println( "Time:"+(endTime -beginTime ));
sc.close();
}
说明:cache()/persist()的位置规定
必须在Transformation或textFile等创建一个RDD后,直接连点调用cache()/persist()。 若先创建一个RDD,再另起一行通过引用调用cache()/persist()是没有用的。
5. 持久化策略——persist()参数StorageLevel指定
持久化级别 | 说明 |
---|---|
MEMORY_ONLY(默认策略) | 以非序列化的Java对象的方式持久化在JVM内存中。若内存无法完全存储RDD所有的partition,则当下次使用到没有被序列化的partition时重新被计算。 |
MEMORY_AND_DISK | 同MEMORY_ONLY,但当某些partition无法存储在内存中时,会持久化到磁盘中。下次需要使用这些partition时,需要从磁盘上读取。 |
MEMORY_ONLY_SER | 同MEMORY_ONLY,但使用序列化的方式持久化对象。 |
DISK_ONLY | 使用非序列化Java对象的方式持久化,完全存储到磁盘上。 |
MEMORY_ONLY_2,MEMORY_AND_DISK_2… | 如果在尾部追加持久化级别2,则将持久化数据复制一份,保存至其他节点。从而在数据丢失时,不需要再次计算,只需要使用备份数据即可。 |
【如何选择】
(1)若可以缓存所有数据,优先使用默认策略MEMORY_ONLY。纯内存速度最快,且没有序列化,不需要消耗CPU进行反序列化操作。
(2)若默认策略无法存储下所有数据,则使用MEMORY_ONLY_SER,将数据序列化进行存储,只是要消耗CPU进行反序列化。
(3)若需要快速的失败恢复,则选择带后缀_2的策略,进行数据备份,以便失败时,不再重新计算。
(4)DISK相关策略是下下策,有时从磁盘读取数据,还不如重新计算一次。