如何在Flink中生成WaterMark
waterMark即水印是Flink中Event Time相关处理的一个重要概念。WaterMark在最大程度上确保了Flink窗口处理中数据的顺序(注意是watermark只是最大程度上确保了数据顺序即一定程度上缓解了数据乱序的问题,某些情况下,数据延迟非常严重即watermark机制也无法确保数据全部进入窗口,关于延迟数据参考allowed lateness机制)。的本文探讨一下如何在Flink中生成WaterMark。
Flink中生成WaterMark需要完成以下4步:
- StreamexecationEvironment指定Timecharacterstic
- Flink程序中指定Event Time时间戳在数据中的字段信息。
- Timestamp Assigning过程,Flink程序通过步骤2所指定额字段抽取对应的Event Time。
- 根据定义的WaterMarks生成策略,生成WaterMarks。
目前Flink支持两种方式指定Timestamps和生成waterMarks: - 在DataStream Source 算子接口的Source Function实现类定义。
- 自定义Timestamp Assigner和Watermark Generator生成。
1. 通过SourceFunction接口定义timestamps和Watermarks
在DataStream Source算子中指定EvenTime时间戳,确保数据在进入到Flink系统中就直接指定分配EventTime和Watermark。
SourceFunction接口java定义如下:
public interface SourceFunction<T> extends Function, Serializable {
/**
* 启动数据源,实现类可以通过SourceContext类型入参ctx发出元素。
* @param ctx 发送元素和接收锁的Context.
*/
public void run(SourceContext<Tuple2<String, Integer>> ctx) throws Exception ;
/**
* 停止DataSource。 大多数源在run(SourceContext ctx)方法内部都会有一个while循环。实现类要确保在调用此方法后,DataSource将能够退出该循环。
* 一种典型的实现模式是:
* 在实现类中定义volatile类型的bool变量(volatile boolean isRunning)作为标志,
* 并在循环中检查该标志。
* 此外停止DataSource时,执行线程也将被中断(通过Thread.interrupt())。 但可确定的是该线程
* 中断是严格发生在调用此方法之后,因此任何中断处理程序都可以认为此方法已经执行完成。
* 一个优雅实践是通过此方法修改所有volatile型的标志,以确保此方法的效果对任何中断处理程序可见
*/
public void cancel();
}
用户实现SourceFunction
接口需实现run()
方法来实现数据生成逻辑。在run()
方法中,调用SourceContext的collectWithTimestamp()
方法生成EventTime时间戳,调用emitWatermark()
方法生成watermarks。
2. 通过Timestamp Assigner和Watermark Generator实现
2.1 通过自带Timestamp assigner指定Timestamp和watermark
如果用户使用Flink定义的外部数据源连接器,就不能再实现SourceFunction接口来生成流数据及相应的event时间和watermark。这种情况需要通过Timestamp Assigner管理数据流中的Timestamp和watermark。
Timestamp分配器一般跟在data source算子后面指定,也可在后续的算子指定。无论如何指定,要保证Timestamp分配器在第一个依赖时间的operator算子之前指定。如果用户在SourceFunction中定义了Timestamp和watermarks的生成逻辑,同时又使用了Timestamp分配器,后者会覆盖前者定义的逻辑。
Watermarks两种生成方式
Flink定义了两种watermarks生成形式,分别是periodic watermarks和puncuated watermarks。periodic watermarks根据设定时间间隔周期性地生成watermarks,而puncuated watermarks是根据接入数据的数量生成。
2.1.1 periodic watermarks
periodic watermarks根据设定时间间隔周期性地生成watermarks,本生成形式要借助AssignerWithPeriodicWatermarks
接口。
Flink系统中有两种模式的Periodic Watermark分配器,分别是升序模和固定时间间隔模式。
(1) 升序模式
Ascending Timestamp分配器会将数据中的Timestamp根据指定字段提取,并用当前的Timestamp作为最小的watermark。这个模式比较适合于事件按顺序生成,没有乱序事件的情况。
升序模式通过AscendingTimestampExtractor
的子类定义。AscendingTimestampExtractor的抽象方法extractAscendingTimestamp定义了如何从元素中抽取Timestamp。
**
* Extracts the timestamp from the given element. The timestamp must be monotonically increasing.
*
* @param element The element that the timestamp is extracted from.
* @return The new timestamp.
*/
public abstract long extractAscendingTimestamp(T element);
子类实现示例