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_2、MEMORY_AND_DISK_2;虽然所有的存储级别都可以通过重新计算丢失的数据实现容错,但是备份机制使得大部分情况下应用无需中断,即数据丢失情况下,直接使用备份数据,而不需要重新计算数据的过程;
 
(5)如果处于大内存或多应用的场景下,OFF_HEAP可以带来以下的好处:
 
     a. 它允许Spark Executors可以共享Tachyon的内存数据;
     b. 它很大程序上减少JVM垃圾回收带来的性能开销;
     c. Spark Executors故障不会导致数据丢失。
 
最后,Spark可以自己监测“缓存”空间的使用,并使用LRU算法移除旧的分区数据。我们也可以通过显式调用RDD unpersist()手动移除数据。
 
 
 

Spark RDD Persistence的更多相关文章

  1. Spark RDD初探(一)

    本文概要 本文主要从以下几点阐述RDD,了解RDD 什么是RDD? 两种RDD创建方式 向给spark传递函数Passing Functions to Spark 两种操作之转换Transformat ...

  2. Spark Rdd coalesce()方法和repartition()方法

    在Spark的Rdd中,Rdd是分区的. 有时候需要重新设置Rdd的分区数量,比如Rdd的分区中,Rdd分区比较多,但是每个Rdd的数据量比较小,需要设置一个比较合理的分区.或者需要把Rdd的分区数量 ...

  3. Spark RDD API详解(一) Map和Reduce

    RDD是什么? RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD.从编程的角度来看,RDD可以简单看成是一个数组.和普通数组的区别是,RDD中的数据是分区存储的,这样不同 ...

  4. Spark RDD aggregateByKey

    aggregateByKey 这个RDD有点繁琐,整理一下使用示例,供参考 直接上代码 import org.apache.spark.rdd.RDD import org.apache.spark. ...

  5. Spark RDD解密

    1.  基于数据集的处理: 从物理存储上加载数据,然后操作数据,然后写入数据到物理设备; 基于数据集的操作不适应的场景: 不适合于大量的迭代: 不适合交互式查询:每次查询都需要对磁盘进行交互. 基于数 ...

  6. Spark - RDD(弹性分布式数据集)

    org.apache.spark.rddRDDabstract class RDD[T] extends Serializable with Logging A Resilient Distribut ...

  7. Spark RDD Operations(1)

    以上是对应的RDD的各中操作,相对于MaoReduce只有map.reduce两种操作,Spark针对RDD的操作则比较多 ************************************** ...

  8. Spark RDD的依赖解读

    在Spark中, RDD是有依赖关系的,这种依赖关系有两种类型 窄依赖(Narrow Dependency) 宽依赖(Wide Dependency) 以下图说明RDD的窄依赖和宽依赖 窄依赖 窄依赖 ...

  9. Spark RDD操作(1)

    https://www.zybuluo.com/jewes/note/35032 RDD是什么? RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD.从编程的角度来看,RD ...

随机推荐

  1. 在sql2008的实例 中 编写存储过程 读取 版本为sql2005 的实例 中的某个数据库里的数据

     --创建链接服务器 exec sp_addlinkedserver   'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 ' exec sp_addlinkedsrvl ...

  2. php递归创建目录

    /** * 递归创建目录 * @param [string] $path [创建的目录] * @return [type] [description] */ function mk_Dir($path ...

  3. Java-Android 之应用停止错误

    在Android在手机上运行的时候: 经常会出现应用程序停止: 一: 因为触发的方法里面没有传值View 对象,方法报错

  4. NHibernate动态加载资源文件

    最近做项目,又用到了以前做过的ORM框架--NHibernate. 此次想要实现的目标: 1.简单SQL用NHibernate的Session的CRUD方法实现 2.复杂SQL用Native SQL实 ...

  5. javascript类继承系列三(对象伪装)

    原理:在子类的构造器上调用超类构造器(父类构造器中的this指向子类实例),js提供了apply()和call()函数,可以实现这种调用 function baseClass() { this.col ...

  6. android网络图片查看器

    package com.itheima.netimageviewer; import java.io.BufferedReader; import java.io.File; import java. ...

  7. 判断ios是app第一次启动

    首次运行的应用程序加入一些help 或者 宣传动画 现在变的很重要了. 一个有用的例子是发送一个分析实例.这可能是一个很好的方法来确定有多少人下载实用应用程序.有人会说:“但是,嘿,苹果AppStor ...

  8. hdoj 2054(A==B)

    注意考虑以下数据: 123  123.0; 0.123  .123; 00.123  0.123; 代码: #include<iostream>#include<cstdio> ...

  9. HUST 4681 String (DP LCS变形)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4681 题目大意:给定三个字符串A,B,C 求最长的串D,要求(1)D是A的字序列 (2)D是B的子序列 ...

  10. DependencyProperty

    <Window x:Class="DependencyPropertyDemo.MainWindow" xmlns="http://schemas.microsof ...