Flink内核原理与实现
上QQ阅读APP看书,第一时间看更新

3.3 数据转换

数据转换在Flink中叫作Transformation,是衔接DataStream API和Flink内核的逻辑结构。DataStream面向开发者,Transformation面向Flink内核,调用DataStream API的数据处理流水线,最终会转换为Transformation流水线,Flink从Transformation流水线开始执行,后边章节会详细介绍。

从DataStream流水线到Transformation流水线的转换示意如图3-7所示。

Transformation有两大类:物理Transformation和虚拟Transformation。在运行时刻,DataStream的API调用都会被转换为Transformation,然后从Transformation转换为实际运行的算子,而虚拟的Transformation则不会转换为具体的算子,如图3-8所示。

Reblance、Union、Split、Select最终并没有形成实体的算子,那么它们去哪儿了?在后边的作业提交章节中会阐述。

Flink内置的Transformation类体系如图3-9所示。

从类图中可以看到,Transformation类是顶层的抽象,所有的物理Transformation继承了PhysicalTransformation,其他类型的Transformation均为虚拟Transformation。

Transformation包含了Flink运行时的一些关键参数:

1)name:转换器的名称,主要用于可视化。

2)uid: 用户指定的uid,该uid的主要目的是在job重启时再次分配跟之前相同的uid,可以持久保存状态。

图3-7 DataStream流水线到Transformation流水线

图3-8 虚拟Transformation被优化后的算子树

3)bufferTimeout:buffer超时时间。

4)parallelism:并行度。

5)id:跟属性uid无关,生成方式是基于一个静态累加器。

6)outputType: 输出类型,用来进行序列化数据。

7)slotSharingGroup: 给当前的Transformation设置Slot共享组。Slot共享参见第9章。

1.物理Transformation

物理Transformation一共有4种,具体如下。

(1)SourceTransformation

从数据源读取数据的Transformation,是Flink作业的起点。SourceTransformation只有下游Transformation,没有上游输入Transformation。

图3-9 Transformation类体系

一个作业可以有多个SourceTransformation,从多个数据源读取数据,如多流Join、维表Join、BroadcastState等场景。

(2)SinkTransformation

将数据写到外部存储的Transformation,是Flink作业的终点。SinkTransformation只有上游Transformation,下游就是外部存储了。

一个作业内可以有多个SinkTransformation,将数据写入不同的外部存储汇总,如计算结果的热数据写入Redis实时查询,历史数据写入HDFS。

(3)OneInputTransformation

单流输入的Transformation(只接收一个输入流),跟上面的SinkTransformation构造器类似,同样需要input和operator参数。

(4)TwoInputTransformation

双流输入的Transformation(接收两种流作为输入),分别叫作第1输入和第2输入。其他的实现同OneInputTransformation,如图3-10所示。

从上图示例中可以看到,TwoInputTransformation的两个上游输出的类型不同。此类型的两个上游输入的数据类型可以相同也可以不同。

2.虚拟Transformation

(1)SideOutputTransformation

SideOutputTransformation在旁路输出中转换而来,表示上游Transformation的一个分流,上游Transformation可以有多个下游SideOutputTransformation,如图3-11所示。

上游的OneInputTransformation分流给下游的多个SideOutputTransformation,每一个SideOutput通过OutputTag进行标识。

图3-10 TowInputTransformation示例

图3-11 SideOutput示例

(2)SplitTransformation

用来按条件切分数据流,该转换用于将一个流拆分成多个流(通过OutputSelector来达到这个目的),当然这个操作只是逻辑上的拆分(它只影响上游的流如何跟下游的流连接)。

构造该转换器,同样也依赖于其输入转换器(input)以及一个输出选择器(outputSelector),但会实例化其父类(StreamTransformation,没有提供自定义的名称,而是固定的常量值Split)。

(3)SelectTransformation

与SplitTransformation配合使用,用来在下游选择SplitTransformation切分的数据流。

(4)PartitionTransformation

该转换器用于改变输入元素的分区,其名称为Partition。因此,工作时除了提供一个StreamTransformation作为输入外,还需要提供一个StreamPartitioner的实例来进行分区。

PartitionTransformation需要特别提及一下,它在Flink DataStream Runtime中和Blink的流处理、批处理的都被使用了。其有一个ShuffleMode,用来统一表示流、批数据Shuffle的模式。对于流而言,ShuffleMode是ShuffleMode.PIPELINED;对于批而言,ShuffleMode是ShuffleMode.BATCH。

(5)UnionTransformation

合并转换器,该转换器用于将多个输入StreamTransformation进行合并,因此该转换器接收StreamTransformation的集合,其名称也在内部被固定为Union,如图3-12所示。

图3-12 UnionTransformation示例

Union运算要求其直接上游输入的数据的结构必须是完全相同的。

(6)FeedbackTransformation

表示Flink DAG中的一个反馈点。简单来说,反馈点就是把符合条件的数据重新发回上游Transformation处理,一个反馈点可以连接一个或者多个上游的Transformation,这些连接关系叫作反馈边。处于反馈点下游的Transformation将可以从反馈点和反馈边获得元素输入。符合反馈条件并交给上游的Transformation的数据流叫作反馈流(Feedback DataStream),如图3-13所示。

图3-13 FeedbackTransformation示意图

FeedbackTransformation的固定名称为Feedback,有两个重要参数:

1)input: 上游输入StreamTransformation。

2)waitTime: 默认为0,即永远等待,如果设置了等待时间,一旦超过该等待时间,则计算结束并且不再接收数据。

实例化FeedbackTransformation时,会自动创建一个用于存储反馈边的集合feedbackEdges。那么反馈边如何收集呢?FeedbackTransformation通过定义一个实例方法——addFeedbackEdge来进行收集。而这里所谓的“收集”就是将下游StreamTransformation的实例加入feedbackEdges集合中(这里可以理解为将两个点建立连接关系,也就形成了边)。不过,这里加入的StreamTransformation的实例有一个要求:当前FeedbackTransformation的实例跟待加入StreamTransformation实例的并行度应一致。

(7)CoFeedbackTransformation

CoFeedbackTransformation与FeedbackTransformation类似,也是Flink DAG中的一个反馈点。两者的不同之处在于,CoFeedBackTransformation反馈给上游的数据流与上游Transformation的输入类型不同,所以要求上游的Transformation必须是TwoInputTransformation。CoFeedbackTransformation是从ConnectedIterativeStreams创建而来的,而ConnectedIterativeStreams由IterativeStream#withFeedbackType设置新的反馈流的数据类型而来,如图3-14所示。

图3-14 CoFeedbackTransformation示意图

在图3-14中,可以看到TwoInputTransformation有两个输入,第1输入的类型为Tuple<String,Long>,反馈流的输入类型为Tuple<String,Long,Integer>。

Transformation作为中介,负责将执行时刻初始化作业所需要的StreamTask类和算子工程(StreamOperatorFactory)构建好,算子作为UDF的执行时容器,这样就能将作业开发和作业运行联系起来了。Transformation、算子、UDF的关系如图3-15所示。

在本例中,OneInputTransformation包装了算子StreamMap,算子StreamMap又包装了UDF。在逻辑上,下游Transformation连接上游Transformation,逻辑上数据是从上游Trans formation流向下游Transformation,实际上是从算子流向算子,在算子内部交给UDF处理。

图3-15 Transformation、算子、UDF的关系

图3-15是OneInputTransformation的示例,TwoInputTransformation与此相同,接下来介绍算子、UDF。