
3.6 数据分区
数据分区在Flink中叫作Partition。本质上来说,分布式计算就是把一个作业切分成子任务Task,将不同的数据交给不同的Task计算。在分布式存储中,Partition分区的概念就是把数据集切分成块,每一块数据存储在不同的机器上。同样,对于分布式计算引擎,也需要将数据切分,交给位于不同物理节点上的Task计算。
StreamPartitioner是Flink中的数据流分区抽象接口,决定了在实际运行中的数据流分发模式,将数据切分交给Task计算,每个Task负责计算一部分数据流。所有的数据分区器都实现了ChannelSelector接口,该接口中定义了负载均衡选择行为。
代码清单3-14 ChannelSelector接口定义

在该接口中可以看到,每一个分区器都知道下游通道数量,通道数量在一次作业运行中是固定的,除非修改作业的并行度,否则该值是不会改变的(此处跟后边容错章节模型中提到的Flink DAG有关系,Flink DAG的拓扑关系是静态的)。
数据分区类体系如图3-35所示。

图3-35 数据分区类体系
1.自定义分区
在API层面上,自定义分区应用在DataStream上,生成一个新的DataStream。
使用用户自定义分区函数,为每一个元素选择目标分区,其使用如代码清单3-15所示。
代码清单3-15 DataStream中使用自定义分区

2. ForwardPartitioner
在API层面上,ForwardPartitioner应用在DataStream上,生成一个新的DataStream。
该Partitioner比较特殊,用于在同一个OperatorChain中上下游算子之间的数据转发,实际上数据是直接传递给下游的。
3. ShufflePartitioner
在API层面上,ShufflePartitioner应用在DataStream上,生成一个新的DataStream。
随机将元素进行分区,可以确保下游的Task能够均匀地获得数据,其使用如代码清单3-16所示。
代码清单3-16 DataStream中使用ShufflePartitioner

4. ReblancePartitioner
在API层面上,ReblancePartitioner应用在DataStream上,生成一个新的DataStream。
以Round-robin的方式为每个元素分配分区,确保下游的Task可以均匀地获得数据,避免数据倾斜,其使用如代码清单3-17所示。
代码清单3-17 DataStream中使用ReblancePartitioner

5. RescalingPartitioner
在API层面上,RescalingPartitioner应用在DataStream上,生成一个新的DataStream。
根据上下游Task的数量进行分区。使用Round-robin选择下游的一个Task进行数据分区,如上游有2个Source,下游有6个Map,那么每个Source会分配3个固定的下游Map,不会向未分配给自己的分区写入数据。这一点与ShufflePartitioner和ReblancePartitioner不同,后两者会写入下游所有的分区,如图3-36所示。

图3-36 Rescaling分区效果示意
其使用如代码清单3-18所示。
代码清单3-18 DataStream中使用RescalingPartitioner

6. BroadcastPartitioner
在API层面上,BroadcastPartitioner应用在DataStream上,生成一个新的DataStream。
将该记录广播给所有分区,即有N个分区,就把数据复制N份,每个分区1份,其使用如代码清单3-19所示。
代码清单3-19 DataStream中使用BroadcastPartitioner

7. KeyGroupStreamPartitioner
在API层面上,KeyGroupStreamPartitioner应用在KeyedStream,生成一个新的KeyedStream。
KeyedStream根据KeyGroup索引编号进行分区,该分区器不是提供给用户来用的。KeyedStream在构造Transformation的时候默认使用KeyedGroup分区形式,从而在底层上支持作业Rescale功能。