FLink之StreamOperator

一、StreamOperator的定义与实现

紧接上文,Transformation负责描述DataStream之间的转换操作,Transformation结构中最主要的组成部分就是StreamOperator

1.1 StreamOperator接口关系图

关系图

由关系图不难看出:不管是OneInputStreamOperator还是TwoInputStreamOperator类型的算子都继承自AbstractStreamOperator基本实现类。在调度和执行task实例是,会通过AbstractStreamOperator提供的入口方法触发和执行Operator,同时AbstractStreamOperator中也定义了所有算子的公共的组成部分,如StreamRuntimeConetxt、OperatorStateBackedn等。对于AbstractStreamOperator如何被SubTask触发执行,会在后续的章节进行详细的介绍。

1.2 StreamOperator接口实现

接口方法

1.2.1 open()方法:

定义当前Operator的初始化方法,在数据元素正式接入
Operator运算之前,Task会调用StreamOperator.open()方法对该算子进行
初始化,具体open()方法的定义由子类实现,常见的用法如调用
RichFunction中的open()方法创建相应的状态变量。

1.2.2 close()方法

当所有的数据元素都添加到当前Operator时,就会调用
该方法刷新所有剩余的缓冲数据,保证算子中所有数据被正确处理

1.2.3 finish()方法

算子生命周期结束时会调用此方法,包括算子操作执行成功、失败、或者取消时。

1.2.4 prepareSnapshotPreBarrier()方法

在StreamOperator正式执行checkpoint操作之前会调用该方法

1.2.5 snapshotState() 方法

当SubTask执行checkpoint操作时会调用该方法,用于触发该Operator中状态数据的快照操作

1.2.6 initializeState()方法

当算子启动或者重启时,该方法初始化状态数据,当恢复作业任务时,算子会从检查点(checkpoint)持久化的数据中恢复数据。

1.3 AbstractStreamOperator的基本实现

AbstractStreamOperator作为StreamOperator的基本实现类,所有的Operator都会继承和实现该抽象方法
AbstractStreamOperator

1.3.1 成员变量StreamConfig config

存储该StreamOperator的配置信息,实际上是对Configuration参数进行的封装。

1.3.2 成员变量Output<StreamRecord> output

定义了当前StreamOperator的输出操作,执行完该算子的所有转换操作后,会通过Output的collect将数据发送到下游

1.3.3 StreamingRuntimeContext runtimeContext

主要定义了UDF函数执行过程中的上下文信息,例如获取累加器、状态数据

1.3.4 private transient KeySelector<?, ?> stateKeySelector1;

DataStream只有经过keyBy()转换生成KeyedStream后,才会设定stateKeySelector1变量信息

1.3.5 private transient KeySelector<?, ?> stateKeySelector2

只有执行两个KeyedStream关联操作时使用,例如两个流进行join操作在AbstractStreamOperator中会保存stateKeySelector2的信息。

1.3.6 AbstractKeyedStateBackend<?> keyedStateBackend

用于存储KeyedState的状态管理后端,默认为HashMapStateBackend。如果配置
RocksDB作为状态存储后端,则此处为RocksDBKeyedStateBackend。

1.3.7 private transient StreamOperatorStateHandler stateHandler

statehanler 对象封装了KeyedStateBackend和OperatorStateBackend用于同一管理StreamOperator的状态

1.3.8 OperatorMetricGroup metrics

同于记录算子层面的监控指标,包括numRecordsIn、numRecordsOut、numRecordsInRate、
numRecordsOutRate等

1.3.9 protected transient LatencyStats latencyStats

用于采集和汇报当前Operator的延迟时状况

1.3.10 protected transient ProcessingTimeService processingTimeService

基于ProcessingTime的时间服务,实现ProcessingTime时间操作,例如获取当前时间,然后创建定时器等等。

1.3.11 private transient IndexedCombinedWatermarkStatus combinedWatermark

在双输入类型的算子中,如果基于事件时间处理乱序数据,会在AbstractStreamOperator中合并输入的Watermark 选择最小的Watermark作为合并后的指标,并存储在 combinedWatermark变量中。

二、OneInputStreamOperator与 TwoInputStreamOperator

StreamOperator根据输入流的数量分为两种类型,即支持单输入
流的OneInputStreamOperator以及支持双输入流的
TwoInputStreamOperator,我们可以将其称为一元输入算子和二元输
入算子。

2.1 OneInputStreamOperator的实现

OneInputStreamOperator定义了单输入流的StreamOperator,常见的实现类StreamMap StreamFlatMap StreamFilter等
找一个具体实现进行查看 如 StreamMap
@Internal
public class StreamMap<IN, OUT> extends AbstractUdfStreamOperator<OUT, MapFunction<IN, OUT>>
        implements OneInputStreamOperator<IN, OUT> {

    private static final long serialVersionUID = 1L;

    public StreamMap(MapFunction<IN, OUT> mapper) {
        super(mapper);
        chainingStrategy = ChainingStrategy.ALWAYS;
    }

    @Override
    public void processElement(StreamRecord<IN> element) throws Exception {
        output.collect(element.replace(userFunction.map(element.getValue())));
    }
}

在StreamFilter算子构造器中,内部的Function类型为
FilterFunction,并设定上下游算子的链接策略为
ChainingStrategy.ALWAYS,也就是该类型的Operator通常都会与上下游
的Operator连接在一起,形成OperatorChain。
在StreamFilter中实现了OneInputStreamOperator的
processElement()方法,通过该方法定义了具体的数据元素处理逻辑。
实际上就是使用定义的filterFunction对接入的数据进行筛选,然后通过
output.collect(element)方法将符合的条件输出到下游算子中。

2.2 TwoInputStreamOperator的实现

TwoInputStreamOperator定义了双输入流类型的StreamOperator
接口实现,常见的实现类有CoStreamMap、HashJoinOperator等算子。
TwoInputStreamOperator接口定义的主要方法实现对两个数据流转换操作的同时,还定义了两条数据流中Watermark和LatencyMarker的处理逻辑

public interface TwoInputStreamOperator<IN1, IN2, OUT> extends StreamOperator<OUT> {
	//  处理输入源1的数据元素方法
	void processElement1(StreamRecord<IN1> element) throws Exception;
	//  处理输入源2的数据元素方法
    void processElement2(StreamRecord<IN2> element) throws Exception;
	//  处理输入源1的数据水位线
    void processWatermark1(Watermark mark) throws Exception;
	//  处理输入源2的数据水位线
    void processWatermark2(Watermark mark) throws Exception;
   
	// 处理输入源1的LatencyMarker(延迟标记)方法
    void processLatencyMarker1(LatencyMarker latencyMarker) throws Exception;

	// 处理输入源2的LatencyMarker(延迟标记)方法
    void processLatencyMarker2(LatencyMarker latencyMarker) throws Exception;
	//  处理输入源1的数据水位线状态
    void processWatermarkStatus1(WatermarkStatus watermarkStatus) throws Exception;
	//  处理输入源2的数据水位线状态
    void processWatermarkStatus2(WatermarkStatus watermarkStatus) throws Exception;
}

以CoStreamMap类的定义和实现为例:

public class CoStreamMap<IN1, IN2, OUT>
        extends AbstractUdfStreamOperator<OUT, CoMapFunction<IN1, IN2, OUT>>
        implements TwoInputStreamOperator<IN1, IN2, OUT> {

    private static final long serialVersionUID = 1L;

    public CoStreamMap(CoMapFunction<IN1, IN2, OUT> mapper) {
        super(mapper);
    }

    @Override
    public void processElement1(StreamRecord<IN1> element) throws Exception {
        output.collect(element.replace(userFunction.map1(element.getValue())));
    }

    @Override
    public void processElement2(StreamRecord<IN2> element) throws Exception {
        output.collect(element.replace(userFunction.map2(element.getValue())));
    }
}

从CoStreamMap算子定义中
可以看出,CoStreamMap继承AbstractUdfStreamOperator的同时,实
现了TwoInputStreamOperator接口。其中在processElement1()和
processElement2()两个方法的实现中,分别调用了用户定义的
CoMapFunction的map1()和map2()方法对输入的数据元素Input1和
Input2进行处理。经过函数处理后的结果会通过output.collect()接
口推送到下游的Operator中。

三、StreamOperatorFactory工厂类

StreamOperator最终会通过StreamOperatorFactory封装到Transformation结构中,并存储在StreamGraph和JobGraph中。直到运行时执行StreamTask时,才会调用StreamOperatorFactory.createStreamOperator()方法在StreamOperatorFactory中定义StreamOperator实例。
StreamOperatorFactory接口:

@PublicEvolving
public interface StreamOperatorFactory<OUT> extends Serializable {

    <T extends StreamOperator<OUT>> T createStreamOperator(
            StreamOperatorParameters<OUT> parameters);
    void setChainingStrategy(ChainingStrategy strategy);
    ChainingStrategy getChainingStrategy();
    default boolean isStreamSource() {
        return false;
    }

    default boolean isLegacySource() {
        return false;
    }

    default boolean isOutputTypeConfigurable() {
        return false;
    }

    default void setOutputType(TypeInformation<OUT> type, ExecutionConfig executionConfig) {}

    default boolean isInputTypeConfigurable() {
        return false;
    }

    default void setInputType(TypeInformation<?> type, ExecutionConfig executionConfig) {}

    Class<? extends StreamOperator> getStreamOperatorClass(ClassLoader classLoader);
}

StreamOperatorFactory继承关系图:
继承关系
StreamOperatorFactory封装创建StreamOperator的操作,在DataStreamAPI中主要通过SimpleStreamOperatorFactory创建已经定义好的Operator ,DataStream API 中大部分操作都是通过

public class SimpleOperatorFactory<OUT> extends AbstractStreamOperatorFactory<OUT> {

    private final StreamOperator<OUT> operator;

    /** Create a SimpleOperatorFactory from existed StreamOperator. */
    @SuppressWarnings("unchecked")
    public static <OUT> SimpleOperatorFactory<OUT> of(StreamOperator<OUT> operator) {
        if (operator == null) {
            return null;
            // 如果Operator是StreamSource类型的且userFunction 为InputFormatSourceFuction
            // 返回SimpleInputFormatOperatorFactory
        } else if (operator instanceof StreamSource
                && ((StreamSource) operator).getUserFunction()
                        instanceof InputFormatSourceFunction) {
            return new SimpleInputFormatOperatorFactory<OUT>((StreamSource) operator);
            // 如果Operator是StreamSink类型,且UserFuction类型为 OutputFormatSinkFuction 
            // 返回SimpleOutputFormatOperatorFactory
        } else if (operator instanceof UserFunctionProvider
                && (((UserFunctionProvider<Function>) operator).getUserFunction()
                        instanceof OutputFormatSinkFunction)) {
            return new SimpleOutputFormatOperatorFactory<>(
                    (((OutputFormatSinkFunction<?>)
                                    ((UserFunctionProvider<Function>) operator).getUserFunction())
                            .getFormat()),
                    operator);
         //  如果Operator是AbstractUdfStreamOperator则返回 SimpleUdfStreamOperatorFactory 
        } else if (operator instanceof AbstractUdfStreamOperator) {
            return new SimpleUdfStreamOperatorFactory<OUT>((AbstractUdfStreamOperator) operator);
            // 如果是其他情况返回SimpleOperatorFactory
        } else {
            return new SimpleOperatorFactory<>(operator);
        }
    }
}

SimpleOperatorFactory.of()方法定义中可以看出,基于StreamOperator提供的of()方法对算子进行工厂类的封装,将Operator封装在OperatorFactory中。然后根据Operator类型的不同,创建不同的SimpleOperator实现类。

  public <T extends StreamOperator<OUT>> T createStreamOperator(
            StreamOperatorParameters<OUT> parameters) {
        if (operator instanceof AbstractStreamOperator) {
            ((AbstractStreamOperator) operator).setProcessingTimeService(processingTimeService);
        }
        if (operator instanceof SetupableStreamOperator) {
            ((SetupableStreamOperator) operator)
                    .setup(
                            parameters.getContainingTask(),
                            parameters.getStreamConfig(),
                            parameters.getOutput());
        }
        return (T) operator;
    }

SimpleOperatorFactory.createStreamOperator()方法创建StreamOperator实例。如果算子同时实现SetupableStreamOperator接口,则会调用setup()方法对算子进行基本的设置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值