Flink源码解析(七)——StreamGraph生成过程解析

一、StreamGraph介绍

在一个Flink流式应用中每个DataStream API调用都会被转换为一个Transformation,等StreamExecutionEnvironment.execute()方法开始执行时,每个Transformation会映射为一个StreamGraph。StreamGraph用来表达计算过程的连接逻辑,与应用具体执行过程无关。下图为一个StreamGraph生成过程样例。从图中可知StreamGraph主要包含2个StreamNode和StreamEdge核心对象。

二、StreamGraph核心对象介绍

1、StreamNode:StreamNode是StreamGraph中的节点,由Transformation转换而来,可以理解成一个StreamNode就表示一个算子计算过程。Transformation分虚拟Transformation和物理Transformation,相应转换成的StreamNode也分为虚拟StreamNode和物理StreamNode。物理StreamNode最终会变成物理的算子,虚拟StreamNode会附着在StreamEdge上。StreamNode可以有多个输入,也可以有多个输出。

2、StreamEdge:StreamEdge是StreamGraph中的边,用来连接2个StreamNode。一个StreamNode可以有多个出边、多个入边。在StreamEdge中包含着OutputTag、StreamPartitioner等必要的边生成信息。

3、StreamGraph主要由StreamNode、StreamEdge组成,下图中StreamGraph几个主要成员变量负责组织StreamNode、StreamEdge的存储。

三、StreamGraph生成的代码调用基本结构

1、StreamGraph生成入口:当Flink应用业务逻辑算子编写完后会直接调用StreamExecutionEnvironment.execute()方法开始任务的生成、提交及调度,第一阶段就是将Transformation转换为StreamGraph。以下方法调用链引出StreamGraph生成入口。最终会定位到StreamGraphGenerator.generate()方法上。

 2、生成StreamGraph主方法StreamGraphGenerator.generate()

(1).首先生成一个空的StreamGraph实例并设置该实例的成员变量属性值,设置完后for循环遍历每一个Transformation,将每个Transformation转换为StreamNode并设置StreamEdge。

(2).transform()方法调用介绍:该方法存在一个嵌套函数递归调用过程。嵌套递归调用结构如下图所示。步骤一针对每一个Transformation会先转换该Transformation上游Transformation,直到Transformation上游为空时,返回空ids列表。进入步骤二处理逻辑中。步骤二就是根据不同Transformation类型用相应TransformationTranslator生成一个个StreamNode及StreamEdge的过程。

 (3).在transform()方法中,首先alreadyTransformed变量存储已被转换完的Transformation,用来快速获取已被转换完的Transformation。其次收集每个Transformation的槽位共享组信息。最后根据Transformation类型,获取不同的TransformationTranslator生成StreamNode、StreamEdge。

 (4).在translate()方法中,可知是先对上游Transformation生成StreamNode、StreamEdge。类似SouceTransformation无上游Transformation时,则生成当前Transformation的StreamNode。

四、不同类型TransformationTranslator举例

下面以OneInputTransformationTranslator、TwoInputTransformationTranslator、SourceTransformationTranslator、UnionTransformationTranslator、PartitionTransformationTranslator、SideOutputTransformationTranslator等6个TransformationTranslator类型解析生成StreamNode、StreamEdge的过程。其中UnionTransformationTranslator、PartitionTransformationTranslator、SideOutputTransformationTranslator为虚拟Transformation的TransformationTranslator,会生成虚拟StreamNode并附着在StreamEdge上。

1、SourceTransformationTranslator:SourceTransformation无上游Transformation且在在生成时也不会添加到StreamExecutionEnvironment.addOperator()方法,即不在StreamExecutionEnvironment.transformations列表中。SourceTransformation一般会直接赋值到下游OneInputTransformation等转换的input成员变量中,上面的嵌套递归函数调用过程会首先作用于SourceTransformationTranslator,将SourceTransformation转换会SteamNode。

(1).SourceTransformationTranslator.translateForStreaming()抽象方法的真实调用过程如下:

SimpleTransformationTranslator.translateForStreaming()

  -> SourceTransformationTranslator.translateForStreamingInternal()

  -> SourceTransformationTranslator.translateInternal()

  -> StreamGraph.addSource()

  -> StreamGraph.addSource()

  -> StreamGraph.addOperator()

  ->StreamGraph.addNode();

configure方法会在StreamNode生成后设置剩余的基本属性及进行一些必要的校验工作。

 (2).在SourceTransformationTranslator.translateInternal()中调用StreamGraph.addSource()方法生成StreamNode。最后以列表的形式返回SourceTransformation.id属性,并在上游transform方法中添加到alreadyTransformed辅助变量中。至此SourceTransformation对应的StreamNode生成完毕。

 (3).如下图所示,新生成一个StreamNode对象并对其成员变量赋值,并记录在steamNodes hash集合中。vertexID来源于SourceTransformation.id,vertexClass为SourceOperatorStreamTask.class。着重记下vertexClass,后续Task生成时会借用vertexClass的值以反射的形式生成Task实例。该方法调用结束返回到StreamGraph.addSource()时,会将vertexID添加到sources集合成员中。

2、OneInputTransformationTranslator:该类型涉及到StreamNode、StreamEdge的创建,SourceTransformationTranslator只会创建StreamNode。

(1).OneInputTransformationTranslator.translateForStreaming()抽象方法的真实调用过程如下:

SimpleTransformationTranslator.translateForStreaming()

  -> OneInputTransformationTranslator.translateForStreamingInternal()

  -> AbstractOneInputTransformationTranslator.translateInternal()

    -> StreamGraph.addOperator(){invokableClass}
    -> StreamGraph.addOperator()

    -> StreamGraph.addNode()
  -> StreamGraph.addEdge(){}

    -> StreamGraph.addEdge()

    -> StreamGraph.addEdge()

    -> StreamGraph.addEdgeInternal()

    -> StreamGraph.createActualEdge();

configure方法会在StreamNode生成后设置剩余的基本属性及进行一些必要的校验工作。

 (2).在translateInternal()方法中StreamGraph.addOperator()方法负责触发生成StreamNode的过程,然后遍历Transformation的上游input,生成一个一个的StreamEdge,并以列表的形式返回该Transformation的id属性,在上游transform方法中添加到alreadyTransformed辅助变量中。

 (3).StreamGraph.addOperator()方法中确定invokableClass值,并且会调用StreamGraph.addNode()方法生成StreamNode。StreamGraph.addNode()解析参照SourceTransformationTranslator中的说明。

 (4).OneInputTransformation是物理Transformation,因此OneInputTransformationTranslator会创建物理StreamNode,进而在StreamGraph.addEdgeInternal()方法中直接走的是StreamGraph.createActualEdge()分支。在createActualEdge()方法中可知会设置默认的数据分区器类型,生成1个StreamEdge,根据StreamEdge上下游节点id信息,将该StreamEdge加入到上游StreamNode出边集合中,并加入到下游StreamNode的入边集合中。

3、TwoInputTransformationTranslator:该类型涉及到StreamNode,并且会为2个上游Transformation分别建StreamEdge以进行连接。

(1).TwoInputTransformationTranslator.translateForStreaming()抽象方法的真实调用过程如下:

SimpleTransformationTranslator.translateForStreaming()

  -> TwoInputTransformationTranslator.translateForStreamingInternal()

  -> AbstractTwoInputTransformationTranslator.translateInternal()

    -> StreamGraph.addCoOperator(){jobVertexClass}

    -> StreamGraph.addNode()

  -> StreamGraph.addEdge(){}

    -> StreamGraph.addEdge()

    -> StreamGraph.addEdge()

    -> StreamGraph.addEdgeInternal()

    -> StreamGraph.createActualEdge();

由代码可知,StreamGraph.addCoOperator()方法调用中生成vertexClass类名称,并调用StreamGraph.addNode()方法生成StreamNode。StreamEdge生成过程参考OneInputTransformationTranslator描述,不再赘述。最终以列表的形式返回该Transformation的id属性,在上游transform方法中添加到alreadyTransformed辅助变量中。

4、UnionTransformationTranslator:

(1)、UnionTransformationTranslator是一个虚拟TransformationTranslator,该TransformationTranslator不生成StreamNode、StreamEdge,仅用来负责连接上游Transformation和下游Transformation。StreamGraph生成结束后UnionTransformation就不存在了。由源码可知translateInternal()方法最后返回的是UnionTransformation上游Transformation的ids信息,最终在alreadyTransformed存储的是{UnionTransformation -> 上游Transformation.ids信息}。而上面前三个TransformationTranslator逻辑过后,alreadyTransformed存储的是{当前Transformation -> 当前Transformation.ids信息}

(2).举例说明UnionTransformationTranslator的具体作用。在alreadyTransformed hash集合中,

ds2_a存储的是{ds2_a:Transformation -> array(ds2_a:Transformation.id)}

ds2_b存储的是{ds2_b:Transformation -> array(ds2_b:Transformation.ids)}

ds3存储的则是{ds3:Transformation -> array(ds2_a:Transformation.id, ds2_b:Transformation.id)}

ds4存储的是{ds4:Transformation -> array(ds4:Transformation.ids)}

在生成StreamEdge过程中,从context.getStreamNodeIds()方法里可知是从alreadyTransformed中获取对应的Transformation.ids信息的。ds4在创建StreamEdge时,上游Transformation是ds3:UnionTransformation,但alreadyTransformed存的是array(ds2_a:Transformation.id, ds2_b:Transformation.id),因此ds4的上游输入边是<ds2_a, ds4>和<ds2_b, ds4>。结果就是StreamGraph生成完毕后,ds3对应的Transformation就不会体现到StreamGraph中了。

5、PartitionTransformationTranslator:

(1)、PartitionTransformationTranslator是一个虚拟TransformationTranslator,该TransformationTranslator不生成StreamNode、StreamEdge,仅用来负责连接上游Transformation和下游Transformation。StreamGraph生成结束后PartitionTransformation就不存在了。

(2).举例说明PartitionTransformationTranslator的作用。假如有以下调用链路:ds1:ds0.map()  ->  ds2:ds1.rebalance()  ->  ds3:ds2.flatMap()。在alreadyTransformed hash集合中,

ds1存储的是{ds1:Transformation -> array(ds1:Transformation.id)}

ds2存储的是{ds2:Transformation -> array(virtualIds)}

ds3存储的是{ds3:Transformation -> array(ds3:Transformation.ids)}

由下图可知virtualPartitionNodes变量中还会记录{virtualIds  ->  Tuple3<ds1:Transformation.ids, partitioner,exchangeMode>}

 (3).ds3如OneInputTransformation在创建StreamEdge时,ds3的parentTransformations是ds2,而在alreadyTransformed中ds2:Transformation对应的value是array(virtualIds),这些virtualIds在virtualPartitionNodes存在,并且对应一个Tuple3,Tuple3.f0是ds1的Transformation.ids信息。因此ds3的调用addEdgeInternal()方法中会走第二个分支,在第二个分支中会替换upStreamVertexID为ds1:Transformation.id,即ds3的入边是<ds1, ds3>。结果就是StreamGraph生成完毕后,ds2对应的Transformation就不会体现到StreamGraph中了。

6、SideOutputTransformationTranslator:SideOutputTransformationTranslator的原理和PartitionTransformationTranslator基本类似,此处不在赘述,自行查看源码理解。

posted @ 2023-11-28 14:22  有一个娃  阅读(114)  评论(0编辑  收藏  举报