Spark-之数据持久化(血缘关系cache\persist\checkpoint)

本文深入探讨了Spark中RDD的数据持久化机制,包括cache和persist的血缘关系利用以及checkpoint的血缘关系切断。当RDD未持久化时,多次action操作会导致重复计算;而通过cache或persist可实现计算重用,减少重复计算。checkpoint则通过写入磁盘切断血缘关系,提高容错效率。代码示例展示了cache、persist和checkpoint的使用及效果。

Spark-之数据持久化(血缘关系 cache\persist\checkpoint)

  • cache
  • persist
  • checkpoint

cache、persist默认都是调用persist(StorageLevel.MEMORY_ONLY)。

1、cache & persist

由于RDD本身是不存储数据的,它只是一个抽象。多个RDD之间可能存在依赖,这种现象被称为RDD的血缘关系,RDD的血缘关系在job触发的时候形成DAG。

1、如果没有将RDD进行持久化。

  • 如果一个RDD同时触发2个action算子的job,那么该RDD及其之前的父RDD都会被重复执行2次!!
  • RDD计算过程中失败之后,Spark的容错机制会从血缘关系的起点开始重新计算整个DAG!!

2、如果经过cache或者persist持久化。

  • 如果一个RDD同时触发2个action算子的job,那么只有触发的第一个job会将整个DAG执行一遍,第二个job会从cache开始计算,这样达到了计算的重用。
  • RDD计算过程中失败之后,Spark的容错机制会从cache开始重新计算整个DAG!!

这种方式不会切断血缘关系!只会在血缘关系中添加一个cache依赖,这种方式需要通过action算子触发!!!

2 、checkpoint

与前者不同,checkpoint需要sc设置检查点目录,而且checkpoint会切断血缘关系,将RDD的最终依赖置为checkpoint,默认情况下checkpoint会在原先action提交的job的基础上再重新触发一个job,也就是2个job,将checkpoint之前的dag重新计算一遍,存在磁盘。

  • 当再checkpoint之前进行cache或者persist操作,那么checkpoint就不会启动另外的job去持久化,而是直接使用cache进行持久化,此时只有1个job
//(1) MapPartitionsRDD[1] at map at CachedDemo001.scala:16 [Memory Deserialized 1x Replicated]
 //|       CachedPartitions: 1; MemorySize: 24.0 B; ExternalBlockStoreSize: 0.0 B; DiskSize: 0.0 B
 //|  ReliableCheckpointRDD[2] at collect at CachedDemo001.scala:32 [Memory Deserialized 1x Replicated]
val rdd = ...
    rdd.cache()
    rdd.checkpoint()

以上是一种优化

这种方式会切断血缘关系,同时需要action算子进行触发,也能实现计算的重用。

3 、简单的代码

package com.shufang.cache

import com.shufang.utils.ScUtil
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.storage.StorageLevel

object CachedDemo001 {
  def main(args: Array[String]): Unit = {
    val sc: SparkContext = ScUtil.getSc

    sc.setCheckpointDir("cp")

    val value: RDD[Int] = sc.makeRDD(1 to 2,1)

    val rdd1: RDD[Int] = value.map {
      int => {
        println("@@@@")
        int * 2
      }
    }

    //查看整个依赖链路,cache before
    println(rdd1.toDebugString)

    //rdd1.cache()
    //rdd1.persist(StorageLevel.DISK_ONLY)
    rdd1.cache()
    rdd1.checkpoint()

    println("==================")
    rdd1.collect()
    rdd1.collect()
    //查看整个依赖链路,cache after
    println(rdd1.toDebugString)

     /** 以上运行结果
     * (1) MapPartitionsRDD[1] at map at CachedDemo001.scala:16 []
     * |  ParallelCollectionRDD[0] at makeRDD at CachedDemo001.scala:14 []
     * ==================
     * @@@@
     * @@@@
     * (1) MapPartitionsRDD[1] at map at CachedDemo001.scala:16 [Memory Deserialized 1x Replicated]
     * |       CachedPartitions: 1; MemorySize: 24.0 B; ExternalBlockStoreSize: 0.0 B; DiskSize: 0.0 B
     * |  ReliableCheckpointRDD[2] at collect at CachedDemo001.scala:32 [Memory Deserialized 1x Replicated]
     */
        
    sc.stop()
  }
}

<think>首先,用户的问题是:“我想在Spark中使用持久化机制时,如何配置使其不将数据存储到磁盘 请问Spark persist or cache without disk storage”。翻译成英文是:“I want to use persistence mechanism in Spark, how to configure it so that data is not stored to disk? Please ask about Spark persist or cache without disk storage.” 用户的核心需求是:在Spark中使用持久化机制时,只使用内存,而不将数据存储到磁盘。这意味着他们希望数据完全在内存中缓存,避免任何磁盘I/O。 现在,回顾系统指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 引用站内信息:[^1], [^2], [^3], [^4]。 引用内容总结: - [^1]: Sparkcachepersist的区别,rdd缓存源码解析。cache()persist()的简写,使用默认存储级别。当第一次标记持久化时,注册到SparkContext进行清理记账。 - [^2]: SparkCheckPointCachePersist的用法、区别。cache就是persistpersist有多种存储级别支持内存或磁盘。persist不切断血缘关系数据出错时可重新计算;checkpoint切断血缘,数据永久保存。 - [^3]: Spark内存管理。Spark内存分为executionstorage。1.6后统一内存管理,存储内存执行内存共享空间,可动态占用。 - [^4]: Spark1.6.0学习心得:shuffle、persistcache、shared variable。cache()是默认存储级别MEMORY_ONLY_SER的简写。存储级别包括MEMORY_ONLY(无序列化)、MEMORY_AND_DISK(内存不足时存磁盘)、MEMORY_AND_DISK_SER(序列化)等。 用户需求的关键是避免磁盘存储。在Spark中,持久化机制通过persist()cache()实现,但需要指定存储级别。 存储级别(StorageLevel)决定了数据如何存储: - MEMORY_ONLY:只存储在内存中,不序列化。如果内存不足,部分分区不会被缓存,需要时重新计算。 - MEMORY_ONLY_SER:只存储在内存中,序列化形式,节省空间但需要CPU反序列化。 - MEMORY_AND_DISK:存储在内存中,内存不足时溢出到磁盘。 - MEMORY_AND_DISK_SER:序列化形式存储,内存不足时溢出到磁盘。 用户想要“without disk storage”,所以应该使用MEMORY_ONLY或MEMORY_ONLY_SER,这些级别不涉及磁盘。 在引用中: - [^2]提到persist支持内存存储。 - [^4]明确说cache()是MEMORY_ONLY_SER的简写。 - 但用户可能想自定义存储级别。 回答步骤: 1. **理解需求**:解释用户想要纯内存持久化。 2. **解决方案**:推荐使用MEMORY_ONLY或MEMORY_ONLY_SER存储级别。 3. **代码示例**:展示如何在Spark中使用persist()cache()指定这些级别。 4. **注意事项**:讨论内存不足时的行为,如数据可能不被缓存。 5. **引用支持**:自然地融入引用。 6. **生成相关问题**:在最后添加相关问题。 使用中文回答。 结构: - 开头:确认用户需求。 - 主体:逐步解释如何配置。 - 结尾:总结生成问题。 引用标识:在相关段落末尾添加[^数字]。 例如: "在Spark中,cache()方法是persist()的简写,默认使用MEMORY_ONLY_SER存储级别[^4]。" 生成相关问题: - 如何选择Spark中的存储级别? - 如果内存不足,MEMORY_ONLY会怎样? - Spark的内存管理如何影响持久化性能? 确保LaTeX正确:用户问题中没有数学表达式,但如果有,需要处理。这里可能不需要。</think>### Spark中配置纯内存持久化(不存储到磁盘) 在Spark中,持久化机制(如`persist()`或`cache()`)用于将RDD或DataFrame缓存到内存或磁盘,以加速后续计算。您的需求是**只使用内存存储,避免任何磁盘写入**。这可以通过指定合适的存储级别(`StorageLevel`)来实现。下面我将逐步解释如何配置,并确保数据不落盘。 #### 1. **理解存储级别需求** - Spark持久化通过`persist()`方法实现,`cache()`是其简写形式(默认使用`MEMORY_ONLY_SER`级别[^4])。 - 存储级别决定了数据如何缓存: - `MEMORY_ONLY`:数据只存储在内存中(未序列化),内存不足时部分分区不会被缓存,需要时重新计算。 - `MEMORY_ONLY_SER`:数据序列化后存储在内存中(节省空间但增加CPU开销),内存不足时同样不写入磁盘。 - `MEMORY_AND_DISK` 或 `MEMORY_AND_DISK_SER`:内存不足时数据会溢出到磁盘,**不符合您的需求**。 - 您的目标是避免磁盘存储,因此应选择`MEMORY_ONLY`或`MEMORY_ONLY_SER`。这些级别不涉及磁盘操作,纯内存缓存[^2][^4]。 #### 2. **配置步骤** - **使用`persist()`指定存储级别**:在代码中显式设置`StorageLevel`为`MEMORY_ONLY`或`MEMORY_ONLY_SER`。 - `MEMORY_ONLY`:适合数据量小或内存充足场景,访问速度快(无需反序列化)。 - `MEMORY_ONLY_SER`:适合数据量大时节省内存,但读取时需反序列化(CPU开销略高)。 - **代码示例**(以Scala为例,Python类似): ```scala import org.apache.spark.storage.StorageLevel val rdd = sc.parallelize(1 to 100) // 示例RDD // 配置为纯内存存储(不落盘) rdd.persist(StorageLevel.MEMORY_ONLY) // 或 StorageLevel.MEMORY_ONLY_SER rdd.count() // 触发缓存操作 ``` - 在PySpark中: ```python from pyspark import StorageLevel rdd = sc.parallelize(range(1, 101)) rdd.persist(StorageLevel.MEMORY_ONLY) rdd.count() ``` - **使用`cache()`的注意事项**:`cache()`默认等价于`persist(StorageLevel.MEMORY_ONLY_SER)`[^4]。如果您不需要序列化,请避免使用`cache()`,改用显式`persist()`指定`MEMORY_ONLY`。 #### 3. **关键注意事项** - **内存不足时的行为**:当使用`MEMORY_ONLY`或`MEMORY_ONLY_SER`时,如果内存不足以容纳所有数据Spark会丢弃部分分区(不缓存到磁盘)。后续计算时,这些分区会重新计算(依赖RDD的血缘关系),不会导致任务失败[^2][^3]。 - **性能优化**: - 确保集群内存充足:监控Spark UI的“Storage”标签,检查缓存大小内存使用率。 - 序列化选择:如果数据压缩率高(如数值型),优先用`MEMORY_ONLY_SER`减少内存占用;如果数据访问频繁,用`MEMORY_ONLY`避免反序列化延迟。 - 统一内存管理:Spark 1.6+ 后,存储内存(Storage)执行内存(Execution)共享空间,可动态调整。通过`spark.memory.fraction`(默认0.6)配置内存池大小,确保存储内存足够[^3]。 - **与Checkpoint的区别**:Checkpoint会切断血缘关系并将数据永久写入磁盘,而`persist()`纯内存缓存不落盘,且程序退出后自动清除缓存[^2]。 #### 4. **验证配置** - **检查缓存状态**:在Spark Web UI中,查看RDD的“Storage Level”列,确认显示为`Memory Deserialized`(对应`MEMORY_ONLY`) 或 `Memory Serialized`(对应`MEMORY_ONLY_SER`),且无`Disk`字样。 - **日志监控**:如果出现`Partition not stored`警告,表示内存不足,部分数据未缓存(但不会写入磁盘)。 通过以上配置,您可以实现纯内存持久化,避免磁盘I/O开销。Spark的内存管理机制会优先使用内存空间,仅在必要时丢弃数据,而非写入磁盘[^3][^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值