Spark RDD Lineage 如何实现容错?
面试怎么回答
RDD 的容错基础是不可变性和 Lineage。Transformation 会形成依赖图,分区丢失时 Spark 沿依赖链重新计算对应分区;窄依赖通常能局部重算,宽依赖跨 Shuffle,恢复范围和网络成本更大。Cache 用于复用和加速,丢失仍可重算;Checkpoint 写入可靠存储并截断 Lineage,用于控制长链路的恢复成本。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
Executor 挂掉以后,Spark 为什么不一定要从头跑完整作业?
因为它记住的不是每个中间结果副本,而是这个分区如何计算出来。
RDD 记录确定性的依赖关系,分区丢失后可以沿 Lineage 重算;但长链路和 Shuffle 会放大恢复成本。
Lineage 记录的是计算关系
RDD 是不可变、分区的数据集合。map、filter、join 等 Transformation 会创建新的 RDD,并记录它依赖哪些父 RDD。某个分区丢失后,调度器可以根据依赖关系重新执行产生该分区所需的任务,而不必把所有中间数据都做多副本保存。
窄依赖更容易局部恢复
窄依赖中,一个父分区通常只被少量子分区使用,例如 map 和 filter。丢失某个子分区时,可以沿着对应父分区局部重算,流水线执行也更容易合并在同一 Stage。
宽依赖会形成 Shuffle 边界
groupByKey、reduceByKey、repartition 和多数 join 会让多个子分区依赖多个父分区,形成 Shuffle。下游恢复可能需要重新拉取 Shuffle 文件;如果文件随 Executor 丢失,还可能重跑上游 Map Stage。Lineage 能恢复,不代表恢复成本低。

Cache 和 Checkpoint 解决不同问题
Cache 或 Persist 保存可复用的 RDD 分区,主要减少重复计算,但缓存丢失后仍可根据 Lineage 重算。Checkpoint 把数据可靠写入存储并截断依赖链,适合迭代算法、流式状态或非常长的 Lineage;它会额外触发物化成本。

一个典型场景
迭代图计算每一轮都依赖上一轮,如果连续执行数十轮,Lineage 会越来越长。某个节点故障后从很早的输入开始回放,恢复时间可能不可接受。可以在合适轮次先 persist 并 materialize,再 checkpoint,平衡正常运行成本与故障恢复时间。
参考资料
- Apache Spark RDD Programming Guide:https://spark.apache.org/docs/latest/rdd-programming-guide.html