大家好,我是雷恩Layne,这是《深入浅出flink》系列的第十三篇文章,希望能对您有所收获O(∩_∩)O
文章目录
我们通常通过DataStream的assignTimestampsAndWatermarks方法引入Watermark,assignTimestampsAndWatermarks方法中要求传入的接口有两种:
- AssignerWithPeriodicWatermarks(周期性生成Watermark的时间戳分配器)
- AssignerWithPunctuatedWatermarks(间断式生成Watermark的时间戳分配器)
它们都是TimestampAssigner(时间戳分配器)接口的子接口。具体继承关系如下图所示:
TimestampAssigner接口只有一个抽象方法extractTimestamp
,这个方法定义了eventTime的提取方式:
public interface TimestampAssigner<T> extends Function {
//element:当前被分配的元素
//previousElementTimestamp:上一个元素的时间戳
//返回值:最新的时间戳(即当前被分配的元素的时间戳)
long extractTimestamp(T element, long previousElementTimestamp);
}
AssignerWithPeriodicWatermarks和AssignerWithPunctuatedWatermarks的实现类,除了要实现它们本身的方法,还有实现TimestampAssigner接口中的extractTimestamp方法。
一、AssignerWithPeriodicWatermarks
AssignerWithPeriodicWatermarks接口是周期性生成Watermark的时间戳分配器,我们可以在程序中设置生成Watermark的周期,如下:
env.getConfig().setAutoWatermarkInterval(100);//设置每100ms生成Watermark
AssignerWithPeriodicWatermarks接口中只有一个方法,即getCurrentWatermark
,源码如下:
public interface AssignerWithPeriodicWatermarks<T> extends TimestampAssigner<T> {
@Nullable
Watermark getCurrentWatermark();
}
系统周期性的调用getCurrentWatermark()
来获取当前的Watermark,它返回的Watermark仅在大于上一次返回的Watermark情况下有效。如果获取的Watermark小于上一次获取的Watermark,则表示当前没有更新的数据到来;如果获取的Watermark是null或者小于上次的Watermark,则表示没有生成新的Watermark。
我们可以自定义类实现AssignerWithPeriodicWatermarks的getCurrentWatermark()
方法,Flink也有给我们实现的工具类,有如下三种:
- BoundedOutOfOrdernessTimestampExtractor
- AscendingTimestampExtractor
- IngestionTimeExtractor
1.1 BoundedOutOfOrdernessTimestampExtractor
BoundedOutOfOrdernessTimestampExtractor
是处理无序数据的时间戳提取器,初始化是会生成一个Watermark,值为Long.MIN_VALUE
,当一个数据到来后,根据extractTimestamp获取不断更新当前最大的时间戳currentMaxTimestamp。然后,周期定的调用getCurrentWatermark获取当前最新的Watermark。
具体源码实现如下:
public abstract class BoundedOutOfOrdernessTimestampExtractor<T> implements AssignerWithPeriodicWatermarks<T> {
private static final long serialVersionUID = 1L;
/** The current maximum timestamp seen so far. */
private long currentMaxTimestamp; //当前最大的时间戳,即已经获取到数据的最大时间戳
/** The timestamp of the last emitted watermark. */
private long lastEmittedWatermark = Long.MIN_VALUE;//上一次发出的Watermark,初始为Long.MIN_VALUE
private final long maxOutOfOrderness;//Watermark的延迟时长
public BoundedOutOfOrdernessTimestampExtractor(Time maxOutOfOrderness) {
if (maxOutOfOrderness.toMilliseconds() < 0) {
throw new RuntimeException("Tried to set the maximum allowed " +
"lateness to " + maxOutOfOrderness + ". This parameter cannot be negative.");
}
this.maxOutOfOrderness = maxOutOfOrderness.toMilliseconds();//延迟时长单位是毫秒
//初始化时,还没有数据到来,需要给currentMaxTimestamp赋一个初值。为了使其小于后面到来数据的时间戳,一般给其赋Long.MIN_VALUE。但是我们求getCurrentWatermark()时,是通过currentMaxTimestamp - maxOutOfOrderness计算的,如果初始的current