|NO.Z.00029|——————————|BigDataEnd|——|Hadoop&Spark.V03|——|Spark.v03|sparkcore|RDD编程高阶&RDD持久化&缓存|
一、RDD持久化/缓存
### --- 涉及到的算子:persist、cache、unpersist;都是 Transformation
~~~ 缓存是将计算结果写入不同的介质,
~~~ 用户定义可定义存储级别(存储级别定义了缓存存储的介质,目前支持内存、堆外内存、磁盘);
~~~ 通过缓存,Spark避免了RDD上的重复计算,能够极大地提升计算速度;
~~~ RDD持久化或缓存,是Spark最重要的特征之一。
### --- 可以说,缓存是Spark构建迭代式算法和快速交互式查询的关键因素;
~~~ Spark速度非常快的原因之一,就是在内存中持久化(或缓存)一个数据集。
~~~ 当持久化一个RDD后,每一个节点都将把计算的分片结果保存在内存中,
~~~ 并在对此数据集(或者衍生出的数据集)进行的其他动作(Action)中重用。
### --- 这使得后续的动作变得更加迅速;
~~~ 使用persist()方法对一个RDD标记为持久化。
~~~ 之所以说“标记为持久化”,是因为出现persist()语句的地方,
~~~ 并不会马上计算生成RDD并把它持久化,而是要等到遇到第一个行动操作触发真正计算以后,
~~~ 才会把计算结果进行持久化;
二、RDD持久化/缓存执行流程

### --- RDD持久化/缓存
~~~ 通过persist()或cache()方法可以标记一个要被持久化的RDD,持久化被触发,
~~~ RDD将会被保留在计算节点的内存中并重用;
~~~ 什么时候缓存数据,需要对空间和速度进行权衡。
~~~ 一般情况下,如果多个动作需要用到某个 RDD,而它的计算代价又很高,
~~~ 那么就应该把这个 RDD 缓存起来;
~~~ 缓存有可能丢失,或者存储于内存的数据由于内存不足而被删除。
~~~ RDD的缓存的容错机制保证了即使缓存丢失也能保证计算的正确执行。
~~~ 通过基于RDD的一系列的转换,丢失的数据会被重算。
~~~ RDD的各个Partition是相对独立的,因此只需要计算丢失的部分即可,并不需要重算全部Partition。
~~~ persist()的参数可以指定持久化级别参数;
~~~ 使用cache()方法时,会调用persist(MEMORY_ONLY),即:
cache() == persist(StorageLevel.1 Memeory_ONLY)
三、源码提取说明
### --- 使用unpersist()方法手动地把持久化的RDD从缓存中移除;
~~~ # 源码提取说明:RDD.scala
~~~ # 199行
/**
* Persist this RDD with the default storage level (`MEMORY_ONLY`).
*/
def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)
/**
* Persist this RDD with the default storage level (`MEMORY_ONLY`).
*/
def cache(): this.type = persist()
~~~ # 源码提取说明:storagelevel.scala
~~~ # 38行
@DeveloperApi
class StorageLevel private(
private var _useDisk: Boolean,
private var _useMemory: Boolean,
private var _useOffHeap: Boolean,
private var _deserialized: Boolean,
private var _replication: Int = 1)
~~~ # 源码提取说明:storagelevel.scala
~~~ # 152行
object StorageLevel {
val NONE = new StorageLevel(false, false, false, false)
val DISK_ONLY = new StorageLevel(true, false, false, false)
val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
val OFF_HEAP = new StorageLevel(true, true, true, false, 1)
四、存储级别
存储级别 | 描述 |
MEMORY_ONLY | 将RDD 作为反序列化的对象存储JVM 中。如果RDD不能被内存装下,一些分区将不会被缓存,并且在需要的时候被重新计算。 默认的缓存级别 |
MEMORY_AND_DISK | 将RDD 作为反序列化的的对象存储在JVM 中。如果RDD不能被与内存装 下,超出的分区将被保存在硬盘上,并且在需要时被读取 |
MEMORY_ONLY_SER | 将RDD 作为序列化的的对象进行存储(每一分区一个字节数组)。 通常来说,这比将对象反序列化的空间利用率更高,读取时会比较占用CPU |
MEMORY_AND_DISK_SER | 与MEMORY_ONLY_SER 相似,但是把超出内存的分区将存储在硬盘上而不是在每次需要的时候重新计算 |
DISK_ONLY | 只将RDD 分区存储在硬盘上 |
DISK_ONLY_2等带2的 | 与上述的存储级别一样,但是将每一个分区都复制到集群的两个结点上 |
五、RDD持久化/缓存
### --- cache RDD 以 分区为单位;程序执行完毕后,系统会清理cache数据;
~~~ # RDD持久化/缓存实验示例
scala> val list = List("Hadoop","Spark","Hive")
list: List[String] = List(Hadoop, Spark, Hive)
scala> val rdd = sc.parallelize(list)
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[22] at parallelize at <console>:26
~~~ # 调用persist(MEMORY_ONLY)
~~~ # 但语句执行到这里,并不会缓存rdd,因为这时rdd还没有被计算生成
scala> rdd.cache()
res16: rdd.type = ParallelCollectionRDD[22] at parallelize at <console>:26
~~~ # 第一次Action操作,触发一次真正从头到尾的计算
~~~ # 这时才会执行上面的rdd.cache(),将rdd放到缓存中
rdd.count()
~~~ # 第二次Action操作,不需要触发从头到尾的计算
~~~ # 只需要重复使用上面缓存中的rdd
scala> rdd.collect().mkString(",")
res17: String = Hadoop,Spark,Hive
### --- job执行UI:http://hadoop02:4040/jobs/job/?id=8
~~~ 被缓存的RDD在DAG图中有一个绿色的圆点。

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
bdv016-spark.v01
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通