【Flink】Flink链化条件及源码分析

一:FLINK的链化优势

   Flink 中的每个算子都可以设置并行度,每个算子的一个并行度实例就是一个 subTask。由于 Flink 的 TaskManager 运行 Task 的时候是每个 Task 采用一个单独的线程,这会带来很多线程切换和数据交换的开销,进而影响吞吐量。为了避免数据在网络或线程之间传输导致的开销,Flink 会在 JobGraph 阶段,将代码中可以优化的算子优化成一个算子链(Operator Chains)以放到一个 Task 中执行。

二:链化的API层操作

    可以在API层全局禁用链化,其操作如下:

evn.disableOperatorChaining();

  也可以在算子中禁用部分算子链化,其操作如下:

 

dataStream.keyBy(0).filter().map().disableChaining()

三:FLINK的链化源码分析

  大家都知道FLINK的执行图,是由StreamGrap---> JobGrap,其链化优化环节就在StreamingJobGraphGenerator类中生成 JobGrap方法中,其源码实现如下:

 private JobGraph createJobGraph() {
        //链化优化方法
        this.setChaining(hashes, legacyHashes);
        this.setPhysicalEdges();
        this.setSlotSharingAndCoLocation();
}

如上面源码可以直接看出,链化的优化在createJobGraph()方法中,其实现的主要方法在  this.setChaining(hashes, legacyHashes)中,其跟踪下去,其方法源码如下:

private void setChaining(Map<Integer, byte[]> hashes, List<Map<Integer, byte[]>> legacyHashes) {
        Iterator var3 = this.streamGraph.getSourceIDs().iterator();
        //循环source节点
        while(var3.hasNext()) {
            Integer sourceNodeId = (Integer)var3.next();
            //创建链化
            this.createChain(sourceNodeId, 0, new StreamingJobGraphGenerator.OperatorChainInfo(sourceNodeId, hashes, legacyHashes, this.streamGraph, (SyntheticClass_1)null));
        }

    }

如上源码中可以看出,其从streamGraph中,循环其source节点,每个source节点创建链化优化,其创建代码在this.createChain(sourceNodeId, 0, new StreamingJobGraphGenerator.OperatorChainInfo(sourceNodeId, hashes, legacyHashes, this.streamGraph, (SyntheticClass_1)null));中,其会把streamGraph 图当做方法参数传递下去,下面我们再看一下下一步 createChain()方法的源码,其实现如下:

//此源码只列出关键步骤
private List<StreamEdge> createChain(Integer currentNodeId, int chainIndex, StreamingJobGraphGenerator.OperatorChainInfo chainInfo) {
        Integer startNodeId = chainInfo.getStartNodeId();
        if (this.builtVertices.contains(startNodeId)) {
            return new ArrayList();
        } else {
            //可以链化的输出边界
            List<StreamEdge> chainableOutputs = new ArrayList();
            StreamNode currentNode = this.streamGraph.getStreamNode(currentNodeId);
            Iterator var9 = currentNode.getOutEdges().iterator();

            StreamEdge nonChainable;
            while(var9.hasNext()) {
                nonChainable = (StreamEdge)var9.next();
                //判断是否可以链化
                if (isChainable(nonChainable, this.streamGraph)) {
                    //若可以就放在可以链化的队列中
                    chainableOutputs.add(nonChainable);
                } else {
                    nonChainableOutputs.add(nonChainable);
                }
            }

            var9 = chainableOutputs.iterator();

            while(var9.hasNext()) {
                nonChainable = (StreamEdge)var9.next();
                transitiveOutEdges.addAll(this.createChain(nonChainable.getTargetId(), chainIndex + 1, chainInfo));
            }

            var9 = nonChainableOutputs.iterator();

           
    }

如上源码所示,此方法是链化的核心方法,它会把streamGrap的图的输出边界进行循坏判断,是否可以链化,若可以链化就放在链化队列中,不能则放在不能链化队列中;其中isChainable(nonChainable, this.streamGraph)这个方法是对链化进行判断的核心方法,也是本节的重点要讲解的方法,我们跟进源码,其实现如下所示

public static boolean isChainable(StreamEdge edge, StreamGraph streamGraph) {
        StreamNode upStreamVertex = streamGraph.getSourceVertex(edge);
        StreamNode downStreamVertex = streamGraph.getTargetVertex(edge);
        //是否可以链化的条件判断都在这
        return 
             downStreamVertex.getInEdges().size() == 1 && 
             upStreamVertex.isSameSlotSharingGroup(downStreamVertex) && 
             areOperatorsChainable(upStreamVertex, downStreamVertex, streamGraph) && 
             edge.getPartitioner() instanceof ForwardPartitioner &&
             edge.getShuffleMode() != ShuffleMode.BATCH && 
             upStreamVertex.getParallelism() == downStreamVertex.getParallelism() && 
             streamGraph.isChainingEnabled();
    }

如上面源码可以看出,是否可以链化要满足七个条件,其条件如下:

1:downStreamVertex.getInEdges().size() == 1  ,下游的算子的入度是否为1;简单的可以理解为必须只能接收上游一个算子的数据

2:upStreamVertex.isSameSlotSharingGroup(downStreamVertex)   是否共享了slot

3:areOperatorsChainable(upStreamVertex, downStreamVertex, streamGraph)   算子是否可以链化

4:edge.getPartitioner() instanceof ForwardPartitioner 算子边界的分区是否为Forward 模式,对于Partitioner,下一章再详解

5:edge.getShuffleMode() != ShuffleMode.BATCH  

6:upStreamVertex.getParallelism() == downStreamVertex.getParallelism()  并行度一致

7:streamGraph.isChainingEnabled();

以上就是是否可以链化的条件判断。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值