spark 中一个非常重要的功能特性就是可以将RDD 持久化到内存中。当对RDD进行持久化操作时,每个节点都会将自己操作的RDD的partition持久化到内存中,并且之后对该RDD的反复使用直接使用内存缓存的partion.这样的话针对一个RDD反复执行多个操作的场景就只要对RDD计算一次即可。后面直接使用该RDD,而不是需要反复多次计算该RDD。
巧妙的使用RDD的持久化甚至在某些场景下。可以将spark应用程序的性能提升10倍。对于迭代式算法和快速交互式应用来说RDD持久话是非常重要的。
要持久化一个RDD。只要调用其cache()方法或者persist方法即可。在该RDD第一次被计算出来时,就会直接缓存在每一个节点。而且spark持久化机制还是自动容错的。如果持久化的RDD的任何partion丢失了,那么soark会自动通过其源RDD使用transformation 操作重新计算该partion。
那么cache方法和persist方法有什么区别呢区别在于 cache 是 persist 方法的一种简化方式。cache()的底层就是调用persist的无参版本。同时调用persist(MEMORY_ONLY),将数据持久化到内存中。如果需要从内存中清除缓存那么可以使用unpersist()方法。
spark自己也会在shuffle 操作时,进行数据持久化。比如写入磁盘,主要是为了在节点失败时,避免需要重新计算整个过程。
假设我们不使用RDD持久话会出现什么呢
由图可知 假设我们需要做两次count 但是没有做持久化的话 需要从hdfs 读取两次如果数据量比较大的话会非常影响性能。
持久化如下:
cache 和persisit 使用 如下
下面给出java 示例:
public class Persist {
static SparkConf conf=new SparkConf().setMaster("local").setAppName("persist");
static JavaSparkContext sc=new JavaSparkContext(conf);
public static void main(String[] args){
// noCache();
cache();
}
public static void noCache(){
JavaRDD<String> list=sc.textFile("C:\\Users\\haha174\\Desktop\\data\\test\\hive-site.xml");
long beginTime=System.currentTimeMillis();
long count=list.count();
System.out.println("无持久化第一次"+(System.currentTimeMillis()-beginTime));
beginTime=System.currentTimeMillis();
count=list.count();
System.out.println("无持久化第二次"+(System.currentTimeMillis()-beginTime));
}
public static void cache(){
JavaRDD<String> list=sc.textFile("C:\\Users\\haha174\\Desktop\\data\\test\\hive-site.xml").cache();
long beginTime=System.currentTimeMillis();
long count=list.count();
System.out.println("持久化第一次"+(System.currentTimeMillis()-beginTime));
beginTime=System.currentTimeMillis();
count=list.count();
System.out.println("持久化第二次"+(System.currentTimeMillis()-beginTime));
}
}
RDD的持久化是可以手动选择不同的持久化策略的。比如可以将RDD持久化到内存中,持久化到磁盘上,使用序列化的方式持久化,多持久化的数据进行多路复用。只要在调用persist()时传入对应的StorageLevel即可。
MEMORY_ONLY:以非序列化的java对象的方式持久化在JVM内存中。如果内存无法完全存储RDD所有的partition,那么那些没有持久化的partition就会在下一次需要使用它的时候,重新被计算。
MEMORY_AND_DISK
同上但是当某些partiition无法存储在内存中时会持久化到磁盘上,下次需要使用这些partition时,需要从磁盘上读取。
MEMORY_ONLY_SER
同MEMORY_ONLY 但是会使用java序列化方式。将java 对象序列化后进行持久化可以减少内存开销。但是需要进行反序列化会增大cpu 开销