Spark两种核心的容错机制:Lineage(血统)和 Checkpointing(检查点)

在 Spark 中,Lineage(血统)Checkpointing(检查点) 是两种核心的容错机制,它们协同工作以确保作业在发生节点故障时能够恢复并继续执行,而无需从头重新运行整个作业。它们解决的问题和实现方式有所不同:

1. Lineage (血统) - 基于逻辑重建的容错

  • 核心思想: Lineage 记录了 RDD(弹性分布式数据集)的生成逻辑。它本质上是一个有向无环图(DAG),描述了:
    • 初始 RDD 是从哪个数据源(如 HDFS 文件)创建的。
    • 一个 RDD 是通过对其父 RDD 应用了哪些转换操作map, filter, join, groupByKey 等)得到的。
    • RDD 之间的依赖关系(窄依赖 - Narrow Dependency / 宽依赖 - Wide Dependency)。
  • 如何用于容错:
    1. 故障发生: 当一个 Executor 节点失败(或其中某个 Task 失败)时,存储在该节点上的 RDD Partition 数据会丢失。
    2. 识别丢失分区: Driver 程序(或负责调度的组件)会检测到有分区丢失。
    3. 利用血统重建: Spark 不是尝试从备份恢复丢失的数据分区(传统方式),而是利用 Lineage DAG:
      • Spark 会回溯 Lineage 图,找到丢失分区的源头(可能是初始数据源,也可能是依赖的中间 RDD)。
      • Spark 根据 Lineage 记录的转换操作逻辑,重新计算(Recompute)那些丢失的分区及其所有依赖的分区(如果必要)。
      • 这个过程只重新计算丢失部分及其依赖链,而不是整个数据集或整个作业。
  • 优点:
    • 高效恢复: 通常只重新计算丢失的小部分数据,尤其是在窄依赖链中,开销相对较小。
    • 零额外存储开销: 不需要为容错而持久化中间数据(除了原始输入数据),节省存储空间。
    • 逻辑清晰: 提供了数据生成过程的完整视图。
  • 局限性:
    • 血统链过长: 如果作业包含非常长的转换序列(特别是很多宽依赖),回溯和重新计算整个链条的代价会非常高,可能接近甚至超过从头开始运行作业的时间。
    • 迭代算法: 在迭代算法(如机器学习训练)中,每一轮迭代都依赖前一轮的结果。Lineage 会记录每一轮的转换,导致血统图随着迭代次数线性增长。一旦失败,需要从第一轮迭代重新计算所有步骤,效率极低。
    • 宽依赖代价高: 重新计算宽依赖(如 groupByKey, join 涉及 Shuffle)本身开销就很大,因为需要重新 Shuffle 大量数据。

2. Checkpointing (检查点) - 基于物理存储的容错

  • 核心思想: Checkpointing 是将 RDD 的物理数据(实际分区内容)持久化到一个可靠的、容错的分布式存储系统(如 HDFS, S3)的过程。它本质上是为 RDD 在特定时刻创建一个全局一致的快照
  • 作用:
    1. 截断血统链: 这是 Checkpointing 最主要的作用。当对一个 RDD 执行 Checkpoint 后:
      • 该 RDD 的数据被物化(Materialize)到可靠存储。
      • Spark 会切断该 RDD 之前的 Lineage 依赖链。这个被 Checkpoint 的 RDD 被视为一个新的“起点”。
      • 后续对该 RDD 的操作,其 Lineage 将从这个 Checkpoint 点开始记录,而不是从原始的源头开始。
    2. 加速故障恢复: 如果后续计算中发生故障,且丢失的分区属于被 Checkpoint 的 RDD 或其下游 RDD,Spark 可以直接从可靠存储中读取 Checkpoint 的数据,而不是根据冗长的原始 Lineage 去重新计算。这大大缩短了恢复时间。
    3. 支持迭代算法: 在迭代算法中,定期对迭代的中间结果(如每 10 轮迭代后的模型 RDD)做 Checkpoint:
      • 将血统链限制在当前迭代轮次内。
      • 发生故障时,可以从最近的 Checkpoint 点恢复(如第 10 轮),只需重新计算第 10 轮之后的迭代,而不是从第 1 轮开始。
  • 触发方式:
    • RDD.checkpoint() 标记一个 RDD 需要进行 Checkpoint。这是一个惰性操作
    • Action 触发: 只有当在该 RDD 或其下游 RDD 上执行了一个 Action(如 count(), saveAsTextFile(), collect())时,Checkpointing 过程才会真正执行。
  • 存储位置: 必须配置为可靠的、容错的存储系统(如 HDFS, S3)。本地文件系统不适合生产环境的 Checkpointing,因为它不具备容错性。
  • cache()/persist() 的区别:
    • cache()/persist() 将 RDD 数据存储在 Executor 的内存或本地磁盘,目的是加速后续对同一 RDD 的重复访问。这些数据在 Executor 失效时会丢失,且不会切断 Lineage。
    • checkpoint() 将数据存储在可靠的分布式存储,目的是容错和截断 Lineage。它通常涉及额外的 I/O 开销(写入远程存储)。执行 checkpoint() 时,Spark 通常会先 persist() 该 RDD 到内存/磁盘(如果可能),以避免在 Checkpointing 过程中重复计算。

Lineage 与 Checkpointing 的协作关系

  1. 默认容错: Spark 默认且主要依赖 Lineage 进行容错。它高效且无需额外存储。
  2. 识别瓶颈: 当作业存在非常长的 Lineage 链(例如复杂转换流程或大量迭代)或包含昂贵的宽依赖操作时,Lineage 的恢复代价变得不可接受。
  3. 引入 Checkpointing: 在这些关键点(例如迭代算法的每 N 轮之后,或在关键的 Shuffle 结果 RDD 上)显式调用 checkpoint()
  4. 截断与加速: Checkpointing 将 RDD 物化到可靠存储,并切断其之前的 Lineage。这显著缩短了故障后需要回溯和重新计算的 Lineage 长度。
  5. 协同恢复: 发生故障时:
    • 如果丢失的分区可以从最近的 Checkpoint 数据中恢复,则直接从可靠存储读取。
    • 如果丢失的分区在 Checkpoint 点之后,则利用 Checkpoint 点之后的(较短的)Lineage 进行重新计算。

总结:容错流程图

                              +-----------------------+
                              |   Spark Application   |
                              +-----------+-----------+
                                          |
                                          | (Defines Transformations)
                                          v
                              +-----------------------+     Records
                              |    Lineage (DAG)       | <--- How Data
                              | (Logical Plan of RDDs) |      is Computed
                              +-----------+------------+
                                          |
                                          | (Executes Actions)
                                          v
                             +--------------------------+
                             |  Executor (Task Runs)     |
                             |  - Processes Data Partit. |
                             +------------+--------------+
                                          |
          +-------------------------------+-----------------+
          | Failure (Node/Task Crash)                      | Success
          |                                                |
          v                                                v
+---------------------+                          +---------------------+
| Lost RDD Partitions |                          |   Job Completes     |
+---------------------+                          +---------------------+
          |
          | Driver Detects Loss
          v
+-------------------------------------------------+
| Spark Consults Lineage DAG for Recovery Plan:    |
|  1. Does a Checkpoint exist for this RDD or an   |
|     ancestor?                                    |
|     * YES: Recover partition from Checkpoint (HDFS/S3)|
|     * NO: Recompute partition using Lineage:     |
|          - Find ultimate source data/ancestor RDD|
|          - Re-apply all recorded transformations |
+-------------------------------------------------+
          |
          v
+---------------------+
|  Recovery Tasks     |
|  (Scheduled on      |
|   healthy nodes)    |
+---------------------+
          |
          v
+---------------------+
|  Job Continues      |
+---------------------+

关键点:

  • Lineage 是基础: 提供了通过重新计算进行容错的能力,通常高效。
  • Checkpointing 是优化: 用于解决 Lineage 在特定场景(长血统、迭代)下恢复效率低下的问题,通过物化数据和截断血统链来实现。
  • 协作: Checkpointing 依赖于 Lineage 来知道需要物化什么数据,并在物化后修改 Lineage(切断之前的链)。恢复时优先使用 Checkpoint 数据,否则回退到 Lineage 重新计算。
  • 成本权衡: Lineage 几乎无存储成本但有潜在高计算恢复成本;Checkpointing 有明确的存储和 I/O 成本但能显著降低恢复计算成本。开发者需要根据应用特性(迭代次数、血统长度、Shuffle 规模)在合适的地方引入 Checkpointing 以达到最佳的容错效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值