随机分区(shuffle)
最简单的重分区方式就是shuffle,通过调用DataStream的.shuffle()方法,将上游数据随机分配到下游的并行任务中。
轮询分区(Round-Robin)
轮询也是常见的重分区方式,通过调用DataStream的.rebalance()方法,将上游的数据平均分配到下游所有的并行任务中。
重缩放分区(rescale)
重缩放分区和轮询分区非常类型,当调用resacle()方法时,底层调用的其实就是Round-Robin算法进行轮询。
不同的是,rescale重缩放分区会将上游不同的数据来源分为不同的“团体”,在下游的同一团体内,对所有slot进行轮询分发。
从底层实现上看,rebalance 和 rescale 的根本区别在于任务之间的连接机制不同。rebalance 将会针对所有上游任务(发送数据方)和所有下游任务(接收数据方)之间建立通信通道,这是一个笛卡尔积的关系;而 rescale 仅仅针对每一个任务和下游对应的部分任务之间建立通信通道,节省了很多资源。
广播(broadcast)
严格意义上来说,广播并不能算作重分区的一种方式,它会将数据在所有分区都保留一份。通过调用.broadCast()方法,将上游输入数据发送到下游所有的并行任务中。
全局分区(global)
全局分区也是一种特殊的分区方式,通过调用.global()方法,会将所有的输入流数据都发送到下游算子的第一个并行子任务中去。这就相当于强行让下游任务并行度变成了 1,所以使用这个操作需要非常谨慎,可能对程序造成很大的压力。
自定义分区
当 Flink 提供的所有分区策略都不能满足用户的需求时, 我们可以通过使用partitionCustom()方法来自定义分区策略。
public class _14CustomPartitionTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 按照奇偶数进行分区
DataStreamSource<Integer> streamSource = env.fromElements(1, 2, 3, 4, 5, 6, 7, 8);
// 参数1:自定义的Partitioner分区器
streamSource.partitionCustom(new Partitioner<Integer>() {
@Override
public int partition(Integer key, int numPartitions) {
return key % 2;
}
}, new KeySelector<Integer, Integer>() { // 参数2:应用分区器的字段,或者直接像keyBy一样直接指定字段或者索引
@Override
public Integer getKey(Integer value) throws Exception {
return value;
}
})
.print();
env.execute();
}
}