Spark RDD Persistence

Spark最为重要的特性之一就是能够在多个操做(Action)之间,将一个或多个RDD关联的数据集(Dataset)以分区(Partition)为单位进行持久化(Persist)或缓存(Cache),存储介质一般是内存(Memory)。
 
被持久化或缓存的RDD A能够在两种状况下被很好地“重复”利用:
 
(1)直接依赖:操做(Action)直接应用于RDD A之上;
(2)间接依赖:操做(Action)间接应用于RDD B之上,而RDD B来源于RDD A;
 
持久化或缓存是迭代式计算和交互式应用的关键技术,一般能够提高10位以上的计算速度。
 
实际应用中,RDD的持久化或缓存选项是经过persist()或cache()发出的,以后若是某个操做(Action)触发该RDD的数据第一次被计算,那么计算的结果数据(也就是该RDD的数据)就会以分区的形式被缓存于计算节点的内存中;并且这些数据是能够实现容错的,若是这个RDD的某些分区数据丢失(由于节点故障),这些分区的数据能够在使用时经过世代信息(Lineage)被自动恢复。
 
RDD的存储形式或存储介质是能够经过存储级别(Storage Level)被定义的。例如,将数据持久化到磁盘、将Java对象序列化以后(有利于节省空间)缓存至内存、开启复制(RDD的分区数据能够被备份到多个节点防止丢失)或者使用堆外内存(Tachyon)。persist()能够接收一个StorageLevel对象(Scala、Java、Python)用以定义存储级别,若是使用的是默认的存储级别(StorageLevel.MEMORY_ONLY),Spark提供了一个便利方法:cache()。
 
存储级别选项以下:
 
 
MEMORY_ONLY 默认选项,RDD的(分区)数据直接以Java对象的形式存储于JVM的内存中,若是内存空间不足,某些分区的数据将不会被缓存,须要在使用的时候根据世代信息从新计算。
MYMORY_AND_DISK RDD的数据直接以Java对象的形式存储于JVM的内存中,若是内存空间不中,某些分区的数据会被存储至磁盘,使用的时候从磁盘读取。
MEMORY_ONLY_SER RDD的数据(Java对象)序列化以后存储于JVM的内存中(一个分区的数据为内存中的一个字节数组),相比于MEMORY_ONLY可以有效节约内存空间(特别是使用一个快速序列化工具的状况下),但读取数据时须要更多的CPU开销;若是内存空间不足,处理方式与MEMORY_ONLY相同。
MEMORY_AND_DISK_SER 相比于MEMORY_ONLY_SER,在内存空间不足的状况下,将序列化以后的数据存储于磁盘。
DISK_ONLY 仅仅使用磁盘存储RDD的数据(未经序列化)。
MEMORY_ONLY_2,
MEMORY_AND_DISK_2, etc.
以MEMORY_ONLY_2为例,MEMORY_ONLY_2相比于MEMORY_ONLY存储数据的方式是相同的,不一样的是会将数据备份到集群中两个不一样的节点,其他状况相似。
OFF_HEAP(experimental) RDD的数据序例化以后存储至Tachyon。相比于MEMORY_ONLY_SER,OFF_HEAP可以减小垃圾回收开销、使得Spark Executor更“小”更“轻”的同时能够共享内存;并且数据存储于Tachyon中,Spark集群节点故障并不会形成数据丢失,所以这种方式在“大”内存或多并发应用的场景下是颇有吸引力的。须要注意的是,Tachyon并不直接包含于Spark的体系以内,须要选择合适的版本进行部署;它的数据是以“块”为单位进行管理的,这些块能够根据必定的算法被丢弃,且不会被重建。
 
注意:使用PySpark(即便用Python开发Spark应用程序)时,全部须要存储的数据都会使用Pickle进行序列化,这种行为与存储级别无关。
 
Spark推荐用户将须要重复使用的RDD经过persist()或cache()显式持久化。同时咱们须要知道,会触发“Shuffle”的操做是特殊的,例如reduceByKey,即便没有用户的显式persist,它也会自动持久化“Shuffle”的中间结果,以防止“Shuffle”过程当中某些节点故障致使整个输入数据被从新计算。
 
那么咱们应该如何选取持久化的存储级别呢?实际上存储级别的选取就是Memory与CPU之间的双重权衡,能够参考下述内容:
 
(1)若是RDD的数据能够很好的兼容默认存储级别(MEMORY_ONLY),那么优先使用它,这是CPU工做最为高效的一种方式,能够很好地提升运行速度;
 
(2)若是(1)不能知足,则尝试使用MEMORY_ONLY_SER,且选择一种快速的序列化工具,也能够达到一种不错的效果;
 
(3)通常状况下不要把数据持久化到磁盘,除非计算是很是“昂贵”的或者计算过程会过滤掉大量数据,由于从新计算一个分区数据的速度可能要高于从磁盘读取一个分区数据的速度;
 
(4)若是须要快速的失败恢复机制,则使用备份的存储级别,如MEMORY_ONLY_二、MEMORY_AND_DISK_2;虽然全部的存储级别均可以经过从新计算丢失的数据实现容错,可是备份机制使得大部分状况下应用无需中断,即数据丢失状况下,直接使用备份数据,而不须要从新计算数据的过程;
 
(5)若是处于大内存或多应用的场景下,OFF_HEAP能够带来如下的好处:
 
     a. 它容许Spark Executors能够共享Tachyon的内存数据;
     b. 它很大程序上减小JVM垃圾回收带来的性能开销;
     c. Spark Executors故障不会致使数据丢失。
 
最后,Spark能够本身监测“缓存”空间的使用,并使用LRU算法移除旧的分区数据。咱们也能够经过显式调用RDD unpersist()手动移除数据。
相关文章
相关标签/搜索