Spark RDD 中的 repartition
和 coalesce
是两种常用的分区调整算子,它们的功能是改变 RDD 的分区数量。以下从源码、原理和使用角度分析它们的异同点。
一、repartition
和 coalesce
的功能与区别
特性 | repartition |
coalesce |
---|---|---|
主要功能 | 调整 RDD 分区数量,可以增加或减少。 | 调整 RDD 分区数量,主要用于减少分区。 |
是否触发 Shuffle | 一定会触发,生成新的分区数据分布。 | 在减少分区时默认不会触发 ,但可以选择触发 Shuffle(shuffle=true )。 |
是否增加分区 | 支持,增加分区会均匀分布数据(Shuffle)。 | 不推荐增加分区,分区数变多时需启用 Shuffle。 |
数据倾斜的影响 | 数据倾斜更低,分区较均匀。 | 不触发 Shuffle 时可能导致部分分区过大。 |
常见使用场景 | 动态增加或减少分区,用于优化性能或并行度。 | 减少分区,常用于窄依赖算子后优化下游性能。 |
二、实现原理
1. repartition
的源码分析
repartition
是通过调用 coalesce
并设置 shuffle = true
实现的,源码位于 RDD.scala
:
scala
def repartition(numPartitions: Int): RDD[T] = {
coalesce(numPartitions, shuffle = true)
}
- 核心逻辑:
- 一定会触发 Shuffle。
- 利用
RangePartitioner
对数据重新分区。 - 保证数据分布更均匀,适合在大规模数据集上动态调整分区。
2. coalesce
的源码分析
coalesce
的实现逻辑同样在 RDD.scala
中,具体如下:
scala
def coalesce(numPartitions: Int, shuffle: Boolean = false): RDD[T] = {
if (shuffle) {
// 使用 Shuffle 重新分区
new CoalescedRDD(this, numPartitions, shuffle = true)
} else {
// 不触发 Shuffle 时,合并分区(窄依赖)
new CoalescedRDD(this, numPartitions, shuffle = false)
}
}
- 核心逻辑:
- 不触发 Shuffle: 直接通过父 RDD 的分区范围,重新分配分区数据(窄依赖),数据不移动。
- 触发 Shuffle: 将数据重新分配到目标分区数,类似
repartition
的逻辑。 - 如果
numPartitions
大于现有分区数,必须启用 Shuffle。
三、Shuffle 触发的影响
-
Shuffle 的作用:
- 数据从一个任务(分区)输出,写入磁盘或通过网络传输到其他任务(分区)。
- 代价高:磁盘 I/O 和网络开销大,但能重新平衡数据分布。
-
repartition
一定会触发 Shuffle:- 原因是其目的是将数据分布均匀到目标分区。
-
coalesce
默认不触发 Shuffle:- 数据保持窄依赖,减少 Shuffle 开销。
- 缺点:分区数据可能不均匀,造成下游任务性能问题。
四、举例说明
数据集
scala
val rdd = sc.parallelize(1 to 100, 10) // 创建一个有 10 个分区的 RDD
1. 使用 repartition
增加分区
scala
val repartitionedRDD = rdd.repartition(20)
println(repartitionedRDD.getNumPartitions) // 输出:20
- 结果分析:
- 数据通过 Shuffle 重新分布到 20 个分区中,分区内数据更均匀。
- 适合用在需要增加并行度的场景。
2. 使用 coalesce
减少分区
scala
val coalescedRDD = rdd.coalesce(5)
println(coalescedRDD.getNumPartitions) // 输出:5
- 结果分析:
- 不触发 Shuffle,直接合并原有分区,数据可能集中在少数分区。
- 适合用在窄依赖算子(如
filter
)后减少分区,提高效率。
3. 使用 coalesce
增加分区(触发 Shuffle)
scala
val shuffledRDD = rdd.coalesce(20, shuffle = true)
println(shuffledRDD.getNumPartitions) // 输出:20
- 结果分析:
- 通过 Shuffle 扩展到 20 个分区,类似
repartition
。 - 不推荐用
coalesce
增加分区,使用repartition
更直观。
- 通过 Shuffle 扩展到 20 个分区,类似
五、优缺点总结
算子 | 优点 | 缺点 |
---|---|---|
repartition |
数据分布均匀,适合动态调整并行度。 | 一定会触发 Shuffle,开销较大。 |
coalesce |
不触发 Shuffle 时性能高,适合减少分区的场景。 | 数据可能不均匀,依赖父 RDD 分区情况。 |
六、面试回答建议
-
核心区别:
repartition
一定会触发 Shuffle,保证均匀分布,适合大数据量操作。coalesce
默认不会触发 Shuffle,减少分区时更高效,但数据可能不均。
-
适用场景:
- 动态调整分区数时,优先考虑
repartition
。 - 过滤或聚合后减少分区时,优先考虑
coalesce
。
- 动态调整分区数时,优先考虑
-
源码理解:
repartition
是对coalesce
的封装,强制启用 Shuffle。coalesce
可根据是否启用 Shuffle 实现不同分区策略。