基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Spark中的宽依赖(Wide Dependency)和窄依赖(Narrow Dependency)

知识点图片

在 Apache Spark 中,宽依赖(Wide Dependency)窄依赖(Narrow Dependency)是描述父 RDD(Parent RDD)与子 RDD(Child RDD)之间分区(Partition)对应关系的核心概念。

理解这两者的区别对于优化 Spark 任务性能、理解 Stage 的划分以及容错机制至关重要。


1. 窄依赖 (Narrow Dependency)

定义:
指父 RDD 的每一个分区最多被子 RDD 的一个分区所使用。即“一对一”或“多对一”(但数据不跨节点流动)。

  • 形象理解: 独生子女。父 RDD 的数据像流水线一样直接流向子 RDD,不需要跨节点传输。
  • 常见算子:
    • map
    • filter
    • flatMap
    • union
    • coalesce (通常情况)
    • join (如果两个父 RDD 已经基于相同的 Partitioners 进行了协同划分/Co-partitioned)
  • 特点:
    • Pipelining(流水线优化): Spark 可以将多个窄依赖操作合并到一个 Task 中执行(例如:先 map 再 filter),数据在内存中直接转换,无需落盘或网络传输。
    • 容错成本低: 如果某个子 RDD 分区丢失,只需要重新计算对应的父 RDD 分区即可,不需要计算所有父分区。

图示:

plaintext
[父分区1] ---> [子分区1]
[父分区2] ---> [子分区2]

2. 宽依赖 (Wide Dependency) / Shuffle Dependency

定义:
指父 RDD 的每一个分区都可能被子 RDD 的多个分区所使用。即“一对多”或“多对多”。

  • 形象理解: 超生/交际花。数据需要在集群中重新洗牌(Shuffle),不同节点的数据需要交换。
  • 常见算子:
    • groupByKey
    • reduceByKey
    • sortByKey
    • distinct
    • repartition
    • join (通常情况,即未协同划分时)
  • 特点:
    • Shuffle(洗牌): 必须发生 Shuffle。数据需要写入磁盘,并通过网络传输到其他节点。这是 Spark 中最消耗性能的操作。
    • Stage 划分界限: 宽依赖是划分 Stage(阶段)的边界。
    • 容错成本高: 如果子 RDD 分区丢失,通常需要重新计算父 RDD 的所有分区,因为数据是混在一起的。

图示:

plaintext
[父分区1] --+--> [子分区1]
            \--> [子分区2]

[父分区2] --+--> [子分区1]
            \--> [子分区2]

3. 核心区别对比表

特性 窄依赖 (Narrow) 宽依赖 (Wide)
分区对应关系 父分区对应 0 或 1 个子分区 父分区对应多个子分区
是否发生 Shuffle (必须 Shuffle)
数据传输 内存中直接流动 (Pipeline) 跨节点网络传输 + 磁盘读写
Stage 划分 在同一个 Stage 内部 划分新 Stage 的边界
常见算子 map, filter, union groupByKey, reduceByKey, repartition
容错恢复 仅重算丢失的那个分区 可能需要重算父 RDD 所有分区

4. 为什么这个区分很重要?

A. Stage 的划分 (DAG Scheduler)

Spark 的 DAGScheduler 会根据依赖关系将 Job 划分为不同的 Stage

  • 划分规则: 从后往前推,遇到宽依赖就切一刀,断开的地方就是一个 Stage 的边界。
  • 结果: 窄依赖会被放入同一个 Stage 中进行流水线执行(TaskSet),而宽依赖则必须等待上一个 Stage 的所有 Shuffle Map Task 完成后,才能开始下一个 Stage。

B. 性能优化

  • 窄依赖快: 因为都在内存中进行,且支持流水线。
  • 宽依赖慢: 涉及磁盘 I/O 和网络 I/O。
  • 优化思路: 尽量减少宽依赖的使用,或者在宽依赖之前先进行数据过滤(filter),减少 Shuffle 的数据量。例如,reduceByKeygroupByKey 性能好,因为 reduceByKey 会在 Shuffle 前进行预聚合(Map 端预聚合),这其实利用了窄依赖的思想来减少宽依赖的数据传输。

C. 容错 (Fault Tolerance)

Spark 的 Lineage(血统)机制依赖于此。

  • 窄依赖中,如果节点故障导致分区丢失,Spark 只需要找到父 RDD 对应的那个分区重算即可,非常快。
  • 宽依赖中,因为数据是混洗的,一个子分区的数据来自所有父分区。如果 Shuffle 的中间结果丢失,可能需要重新运行整个上游 Stage。

总结

窄依赖是 Spark 速度的保证(内存计算、流水线),宽依赖是 Spark 复杂逻辑的实现(聚合、排序),但也是性能瓶颈的所在。

00:00
00:00