目录
[1. Shuffle(随机分区)](#1. Shuffle(随机分区))
[2. Rebalance(轮询分区)](#2. Rebalance(轮询分区))
[3. Rescale(分组轮询分区)](#3. Rescale(分组轮询分区))
[4. Broadcast(广播分区)](#4. Broadcast(广播分区))
[5. Global(全局分区)](#5. Global(全局分区))
[6. PartitionCustom(自定义分区)](#6. PartitionCustom(自定义分区))

Scala
package transform
import org.apache.flink.api.common.functions.Partitioner
import org.apache.flink.streaming.api.functions.source.{RichParallelSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala._
import source.ClickSource
/**
*
* @PROJECT_NAME: flink1.13
* @PACKAGE_NAME: transform
* @author: 赵嘉盟-HONOR
* @data: 2025-05-19 3:56
* @DESCRIPTION
*
*/
object 物理分区算子 {
def main(args: Array[String]): Unit = {
val env=StreamExecutionEnvironment.getExecutionEnvironment
val data=env.addSource(new ClickSource)
//洗牌(随机)
data.shuffle.print("shuffle").setParallelism(4)
//发牌(轮询)
data.rebalance.print("rebalance").setParallelism(4)
//发牌(分组轮询)
val dataRescale=env.addSource(new RichParallelSourceFunction[Int] {
override def run(sourceContext: SourceFunction.SourceContext[Int]): Unit = {
for(i <- 0 to 7){
if(getRuntimeContext.getIndexOfThisSubtask==(i+1)%2) sourceContext.collect(i+1)
}
}
override def cancel(): Unit = ???
})
dataRescale.rescale.print("rescale").setParallelism(4)
//广播(复制多份)
data.broadcast.print("broadcast").setParallelism(4)
//全局分区(所有数据分发到第一个并行子程序)
data.global.print("global").setParallelism(4)
//自定义分区(分区器:指定分区,选择器:提取当前分区字段)
val dataPartition=env.fromElements(1,2,3,4,5,6,7,8)
dataPartition.partitionCustom(new Partitioner[Int] {
override def partition(k: Int, i: Int): Int = k%2
},data=>data).print("partitionCustom").setParallelism(4)
env.execute("物理分区算子")
}
}
在 Apache Flink 中,物理分区算子(Physical Partitioning Operators)用于控制数据在并行任务之间的分发方式。这些算子可以影响数据流的分区策略,从而优化任务的并行执行和负载均衡。以下是对代码中使用的物理分区算子的详细解释和拓展总结:
1. Shuffle(随机分区)
-
算子 :
shuffle -
作用: 将数据随机分发到下游的并行任务中。每个元素被随机分配到任意一个并行子任务。
-
适用场景 : 当数据分布均匀且没有特定的分区需求时,可以使用
shuffle来实现负载均衡。 -
代码示例 :
Scaladata.shuffle.print("shuffle").setParallelism(4)
2. Rebalance(轮询分区)
-
算子 :
rebalance -
作用: 将数据均匀地轮询分发到下游的并行任务中。每个元素依次分配到下一个并行子任务。
-
适用场景 : 当需要均匀分布数据到所有并行任务时,可以使用
rebalance。 -
代码示例 :
Scaladata.rebalance.print("rebalance").setParallelism(4)
3. Rescale(分组轮询分区)
-
算子 :
rescale -
作用 : 将数据在局部范围内进行轮询分发。与
rebalance不同,rescale只在部分并行任务之间进行轮询,而不是全局。 -
适用场景 : 当数据源和下游任务的并行度不一致时,可以使用
rescale来优化数据分发。 -
代码示例 :
ScaladataRescale.rescale.print("rescale").setParallelism(4)
4. Broadcast(广播分区)
-
算子 :
broadcast -
作用: 将数据复制并广播到所有的下游并行任务中。每个并行子任务都会接收到完整的数据集。
-
适用场景 : 当所有并行任务都需要完整的数据集时,可以使用
broadcast。 -
代码示例 :
Scaladata.broadcast.print("broadcast").setParallelism(4)
5. Global(全局分区)
-
算子 :
global -
作用: 将所有数据发送到下游的第一个并行任务中。其他并行任务不会接收到任何数据。
-
适用场景 : 当需要将所有数据集中处理时,可以使用
global。 -
代码示例 :
Scaladata.global.print("global").setParallelism(4)
6. PartitionCustom(自定义分区)
-
算子 :
partitionCustom -
作用 : 允许用户自定义分区策略。用户需要实现
Partitioner接口来定义如何将数据分发到不同的并行任务。 -
适用场景 : 当有特定的分区需求时,可以使用
partitionCustom来实现自定义的分区逻辑。 -
代码示例 :
ScaladataPartition.partitionCustom(new Partitioner[Int] { override def partition(k: Int, i: Int): Int = k % 2 }, data => data).print("partitionCustom").setParallelism(4)
拓展总结:
- 负载均衡 :
shuffle和rebalance是常用的负载均衡策略,适用于大多数场景。 - 数据局部性 :
rescale可以在局部范围内优化数据分发,减少跨节点的数据传输。 - 数据复制 :
broadcast适用于需要将数据复制到所有并行任务的场景,但会增加网络开销。 - 数据集中处理 :
global将所有数据集中到一个任务中,适用于需要全局处理的场景。 - 自定义分区 :
partitionCustom提供了最大的灵活性,允许用户根据业务需求自定义分区策略。
注意事项:
- 并行度设置: 在使用这些分区算子时,需要注意并行度的设置,以确保数据能够正确地分发到各个并行任务中。
- 性能影响: 不同的分区策略会对性能产生不同的影响,特别是在数据量较大时,选择合适的分区策略可以显著提高任务的执行效率。
通过合理使用这些物理分区算子,可以有效地控制数据流的分发方式,优化 Flink 任务的并行执行和负载均衡。