Flink源码解析(三)——DataStream和Transformation解析
一、DataStream介绍
1、DataStream是一个面向Flink应用开发人员的逻辑概念,它提供了map()、filter()、flatMap()等常见的api接口。Flink应用开发人员通过自定义UDF Function逻辑来表达业务逻辑。
2、DataStream类包含2个重要的成员变量StreamExecutionEnvironment environment和Transformation<T> transformation。DataStream的Transformation成员表示该DataStream从上游的DataStream使用该Transformation而来。
3、常见的DataStream实现类包括:DataStream、DataStreamSource、DataStreamSink、KeyedStream、WindowedStream、ConnectedStreams、BroadcastStream、BroadcastConnectedStream等,分别由特定api调用生成。
二、Transformation介绍
1、Transformation是衔接DataStream API和Flink内核的逻辑结构。DataStream的api调用只是表达每个步骤的业务逻辑处理,并不关心各个业务逻辑之间的数据上下游关系。Flink引入Transformation概念来表达上下游关系,将各个步骤的业务逻辑组织成一个流水线。但Transformation不关心数据执行时刻涉及的物理来源、序列化、转发等行为,运行时刻的行为交由Flink算子概念去处理。Flink算子负责从上游获取数据、交给UDF执行、转发UDF结果数据给下游等具体行为,并负责容错方面的支持。以下为api调用UDF、算子、Transformation的关系图。
2、Transformation分两大类:物理Transformation和虚拟Transformation。物理Transformation在运行时刻会转换为具体的算子,主要包括SourceTransformation、OneInputTransformation、TwoInputTransformation、SinkTransformation等。虚拟Transformation在运行时刻不会转换为算子,主要包括SideOutputTransformation、PartitionTransformation、UnionTransformation等。
3、Transformation关键成员变量说明:
protected final int id; //每个Transformation唯一id标识,基于AtomicInteger ID_COUNTER静态累积器生成
protected String name; //Transformation名称,主要用户可视化展示及日志打印
protected TypeInformation<T> outputType; //输出类型,用于序列化数据
private int parallelism; //并行度
private int maxParallelism = -1; //状态分组key group有关
private String uid; //用户指定的uid值,主要目的是在job重启时再次分配跟之前相同的uid
private String userProvidedNodeHash; //用户提供的node hash,用户生成JobGraph图节点JobVertex的JobVertexID属性值。
protected long bufferTimeout = -1; //数据缓冲时间
private Optional<SlotSharingGroup> slotSharingGroup; //Slot共享组标识
三、API调用到Transformation转换过程
1、SourceTransformation转换过程
首先调用StreamExecutionEnvironment.fromSource()方法创建DataStreamSource类型的DataStream。
其次在创建DataStream过程中,会创建SourceTransformation,并设置DataStream的2个关键成员变量environment和transformation。
如图可见SourceTransformation继承于PhysicalTransformation。
2、OneInputTransformation转换过程
DataStream的map()、flatMap()、filter()、process()等api调用会生成OneInputTransformation,以flatMap()为例说明OneInputTransformation转换过程。调用flatMap()方法后会生成"Flat Map"、outType等内容为transformation成员变量赋值。不同api调用最后都会统一到transform()方法和doTransform()方法调用上。
OneInputTransformation有一个Transformation<IN> input成员变量,代表本Transformation由上游Transformation生成而来。每个DataStream都有一个Transformation对象,表示该DataStream从上游的DataStream使用该Transformation而来。DataStream flatMapS = ds.flatMap(new FlatMap(){xxx});。DataStream ds通过flatMap调用生成resultTransform,将resultTransform赋值给returnStream的transformation变量,并返回returnStream。
getExecutionEnvironment().addOperator(resultTransform);//此行代码调用会将resultTransform添加到StreamExecutionEnvironment的transformations集合列表中,transformations收集每个DataStream api调用生成的Transformation,将业务逻辑串联起来。后续生成StreamGraph、JobGraph时会用到该集合列表。
3、TwoInputTransformation转换过程
2个DataStream的connect方法调用会生成ConnectedStreams实例,在该实例上调用map()、flatMap()、process()等api会生成TwoInputTransformation。以map()调用为例,最终会调用transform()方法和doTransform()方法。
doTransform()方法调用会生成TwoInputTransformation实例进而生成DataStream returnStream实例并返回。
getExecutionEnvironment().addOperator(transform);//会将transform添加到StreamExecutionEnvironment的transformations集合列表中。
4、SinkTransformation转换过程
调用DataStream.sinkTo()方法会生成DataStreamSink实例,在生成过程中会创建SinkTransformation实例并赋值给DataStreamSink.transformation成员变量。并且依旧会将transform添加到StreamExecutionEnvironment的transformations集合列表中。
5、UnionTransformation转换过程
以UnionTransformation为例展示虚拟Transformation转换过程。调用DataStream.union(...)方法时,方法内部会生成一个Transformation集合变量,将union(...)入参涉及的多个DataStream的transformation成员加入该集合并利用该集合生成UnionTransformation实例,最后设置到结果DataStream的transformation成员中。
由此可见虚拟Transformation只是借用上游DataStream的transformation成员封装而来,在生成过程中不会实例化算子变量,而物理Transformation在生成过程中会生成算子变量。