flink dataStream API 的shuffle方式有
1、均匀分区(随机分区)stream.shuffle
ShufflePartitioner源码2、负载均衡分区(轮询分区) stream.rebalance。上游的每个分区数据按照下游分区个数轮询选择一个下游分区发放数据
RebalancePartitioner源码3、可伸缩分区 stream.rescale.flink根据资源使用情况动态调节同一作业的数据分布,根据物理实例部署时的资源共享情况动态调节数据分布,目的是让数据尽可能的在同一 solt 内流转,以减少网络开销。下面截图说明说明分区的调整。
例如 stream.setParallelism(4).rescale.print().setParallelism(2) 前面会4个分区,后面算子只有2个分区。那么前面4个分区会映射到后面的2个分区中。例如4中的0,1 映射到后面的 0 分区,2,3映射到后面1分区。
反过来例如 stream.setParallelism(2).rescale.print().setParallelism(4) 前面有2个分区,后面算子有4个分区,那么前面的0号分区会选择后面的0,1分区发数据。 1号分区会选择后面的2,3号分区发数据。
总之不同于上面2种的是上游4个分区中的数据不会分到下游的多个分区中。这样做的好处是,尽量将数据计算本地化。
如果感兴趣是上游是怎么选择下游partition 可以跟踪下源码。
以stream.setParallelism(3).rescale.print().setParallelism(6) 跟踪如下
1、首先会循环每个print 并行度。总共有6个,对应6个执行点。然后循环每个执行点。去设置每个执行点的souce.
ExecutionJobVertex.connectToPredecessors
ExecutionJobVertex.connectToPredecessors 选择的时候把soruce也传过去2、ExecutionVertex.connectSource.在flink中单个oprate可以理解为一个节点(vertex).从一个oprate 到另一个oprate可以理解为一个边(edge).下游有多少并行度那么从上游到下游就会有多少edge.每个edge描述了他的source是哪个分区数据,以及他的下游也是就是consumer 有哪些分区。虽说是这里会有6个edge但是6个edge里面的soucre是有相同的。所以代码中ee.getSource().addConsumer(ee, consumerNumber)会有对同一个soucre patition添加sonsumer.从这里大概就看明白上游是怎么选择下游partition的了
构建edge以及设置edge的3、经过这个部分之后source的每一个partion就知道他对应下游的那些分区并通过partion算法去选择下游partion进行分区。这里numberOfOutputChannels是2 也就是第二步代码ee.getSource().addConsumer(ee, consumerNumber)为source设置的consumer的个数。而对于shuffle和rebalance numberOfOutputChannels 都是6.所以每个上游分区都会有数据发送到下游的每个分区。而不是固定的那几个。
RescalePartitioner源码4、广播分区,前面分区策略的都是上游选择下游的一个分区发送数据,广播就是上游的一条数据会发送到下游的每个分区。
stream.setParallelism(1).broadcast.print().setParallelism(6)
5、自定义分区
需要实现org.apache.flink.api.common.functions.Partitioner
override def partition(key:String, numPartitions:Int):Int = {
//根据 key 去定义逻辑进行分区 总共有umPartitions个分区,分区序号就是[0 ~ umPartitions-1]
}
网友评论