一、知识铺垫
a. flink数据传输分类
flink数据传输分为 组件之间的通信消息传输 和 算子之间的流数据传输。
(1)组件之间
组件(即client、jobmanager、taskmanager)之间的通信消息传输采用akka框架。常见的通信包括心跳检测、状态上报、指标统计、作业提交和部署等。
(2)算子之间
(2.1)本地线程内(同一个subtask内的两个operator):数据传输通过方法调用进行,即上游算子处理完数据后,直接调用下游算子的processelement方法。
(2.2)本地线程间(同一个taskmanager的不同subtask中):数据传输通过本地内存进行,需要进行数据的序列化和反序列化。
(2.3)跨网络(不同taskmanager的subtask中):采用netty框架,通过socket进行数据传输,也需要进行数据的序列化和反序列化。
flink中为上下游subtask之间数据传输(即上述2.2&2.3)提供了九种传输策略。
其中binaryhashpartitioner位于blink的table api的org.apache.flink.table.runtime.partitioner包中,是一种针对binaryrowdata的哈希分区器。
本文讨论上图中绿色框圈中的八种策略。
在flink webui中,可看到算子之间的传输策略会在箭头上标注出来。
b. flink中分发模式(distribution pattern)
flink 中的执行图可以分成四层:streamgraph -> jobgraph -> executiongraph -> 物理执行图。
在streamgraph -> jobgraph的过程中,上下游subtask之间的数据传输涉及分发模式。
分发模式描述了上游节点与下游节点连接的方式,flink 中有两种分发模式:点对点 (pointwise) 和全连接 (all-to-all)。
all-to-all模式: 简单的全连接。
pointwise模式:上下游节点的并行度会影响连接方式。当上下游并行度相同时会一对一连接;当上游并行度小于下游时,下游subtask只会连接一个上游分区;当上游并行度大于下游时,下游subtask会连接多个上游分区。
rescalepartitioner和forwardpartitioner 采用了 pointwise模式。
在rescalepartitioner&rebalancepartitioner,forwardpartitioner&globalpartitioner 这两组策略中,由于分发模式的不同,每组的两种分区策略会产生不同的效果。
二、八种传输策略
streampartitioner继承自channelselector接口。这里的channel可以认为它就是下游算子的并发实例(即物理分区)。所有streampartitioner的子类都要实现selectchannel()方法,用来选择分区号。
1. forwardpartitioner
forwardpartitioner是flink默认的传输策略。
这种策略的前提是上下游并行度相同。
forwardpartitioner会将数据发到下游的对应分区(在pointwise模式下下游的0号分区也对应着上游相关分区)。
2. rebalancepartitioner
当上下游算子不符合forwardpartitioner使用条件时,flink会默认选择rebalancepartitioner。
(forwardpartitioner & rebalancepartitioner 是flink根据上下游并行度设置等因素设置的默认策略,其他几类传输策略则需要用户代码指定 )。
rebalancepartitioner会先随机选一个下游分区,之后轮询(round-robin)遍历下游所有分区进行数据传输。
3. rescalepartitioner
rescalepartitioner在pointwise模式下会先根据上下游并行度进行匹配,再从匹配后的下游中从0号分区轮询传输数据。
4. shufflepartitioner
shufflepartitioner会随机选取下游分区进行数据传输。由于random生成的随机数符合均匀分布,因此能够大致保证下发的平均效果,类似于rebalancepartitioner。
5. keygroupstreampartitioner
keygroupstreampartitioner的分区是根据消息的key值经过两层hash处理后获得的,具体值如下
mathutils.murmurhash(key.hashcode()) % maxparallelism * numberofchannels / maxparallelism
6. globalpartitioner
globalpartitioner和forwardpartitioner的代码类似。但是globalpartitioner基于all-to-all的分发模式,能获得下游算子的全局分区号。所以保证了只下发给下游算子的第一个分区。
7. broadcastpartitioner
broadcastpartitioner会下发给下游的每个分区,不需要选择。
8.custompartitionerwrapper
custompartitionerwrapper需要用户指定为消息的每个key设置下游分区的选择规则。
三、参考资料
发表评论