flink 不设置水印_flink中的两种水印

在flink中的时间窗口中有个重要概念,就是watermark,也就是我们经常谈论的水印,这里我们不对水印的概念和使用方式进行介绍,这里从源码的角度来看,如何不断的生成水印。

在flink中,有两种水印TimestampsAndPunctuatedWatermarksOperator

TimestampsAndPeriodicWatermarksOperator

我们编写原因水印的代码如下:

//抽取timestamp和生成watermarkDataStream> waterMarkStream =

inputMap.assignTimestampsAndWatermarks(

new AssignerWithPeriodicWatermarks>() {

Long currentMaxTimestamp = 0L;

final Long maxOutOfOrderness = 10000L; // 最大允许的乱序时间是10s

@Nullable

@Override

public Watermark getCurrentWatermark() {

return new Watermark(currentMaxTimestamp - maxOutOfOrderness);

}

//定义如何提取timestamp@Override

public long extractTimestamp(Tuple2 element, long previousElementTimestamp) {

long timestamp = element.f1;

return timestamp;

}

});

TimestampsAndPunctuatedWatermarksOperator

是一个流运算符,生成水印是根据输入的元素,没输出一个元素,就会输出一个水印,如果不想输出水印,那么就输出一个null,核心代码

public void processElement(StreamRecord element) throws Exception {

final T value = element.getValue();

// 通过用户的代码获取到事件时间,注入到element里面就直接往下个opeartor发送final long newTimestamp = userFunction.extractTimestamp(value,

element.hasTimestamp() ? element.getTimestamp() : Long.MIN_VALUE);

output.collect(element.replace(element.getValue(), newTimestamp));

//通过用户代码获取水印,这里会判断水印是否为null//不为null的就直接往下游emit 了final Watermark nextWatermark = userFunction.checkAndGetNextWatermark(value, newTimestamp);

if (nextWatermark != null && nextWatermark.getTimestamp() > currentWatermark) {

currentWatermark = nextWatermark.getTimestamp();

output.emitWatermark(nextWatermark);

}

}

上面的方法中,我们每一个元素的处理,都会调用processElement 方法,参数就是处理的灭一个元素,方便内部主要做下面几件事:

1、从用户的代码中获取事件时间,然后注入到element中,然后发送到下一个operator中

2、通过用户的代码获取定义的水印,如果水印不为null,那么就emit到下游

根据上面的分析,我们可知,如果存在水印,那么每一个元素后就会输出一个水印。

TimestampsAndPeriodicWatermarksOperator

这也是一个流操作,定义水印的生成方式,从类名字中的periodic,我们可以猜测这是一个周期性生成水印的操作,我们从类中看核心代码:

public void open() throws Exception {

super.open();

currentWatermark = Long.MIN_VALUE;

// 获取周期性生成水印的间隔watermarkInterval = getExecutionConfig().getAutoWatermarkInterval();

// 周期性水印,是通过处理时间来实现的,一开始会获取当前的真实时间+我们设置的水印间隔 来作为一个定时触发器if (watermarkInterval > 0) {

// 获取当前的处理时间long now = getProcessingTimeService().getCurrentProcessingTime();

getProcessingTimeService().registerTimer(now + watermarkInterval, this);

}

}

open 方法时这个类的初始化方法,我们可以从上面的代码中看到,在open方法中,先从我们的环境配置中获取周期生成水印的时间间隔watermarkInterval ,如果时间间隔大于0,那么就获取当前的时间,然后注册一个process定时器,下次触发的时间是now+watermarkInterval ,从这里我们可以看到,这个类生成水印是需要借助processTime服务的。

// 到了一定的间隔时间 会触发onProcessingTime 这个方法里面的内容@Override

public void onProcessingTime(long timestamp) throws Exception {

// register next timerWatermark newWatermark = userFunction.getCurrentWatermark();

if (newWatermark != null && newWatermark.getTimestamp() > currentWatermark) {

currentWatermark = newWatermark.getTimestamp();

// emit watermark 发送一个水印output.emitWatermark(newWatermark);

}

// 继续注册一个以当前时间+间隔,作为一个定时器 ,这样一个周期性触发水印往下游发送的实现就完成了long now = getProcessingTimeService().getCurrentProcessingTime();

getProcessingTimeService().registerTimer(now + watermarkInterval, this);

}

onProcessingTime 这个方法时到了定时器触发的时候,会调用这个方法。这个方法主要作用如下:

1、从用户的代码中获取watermark,如果存在watermark,并且时间大于currentWatermark,那么就emit一个水印到下游。

2、获取当前时间now,然后用now+watermarkInterval 继续注册一个process定时器。

public void processElement(StreamRecord element) throws Exception {

// 获取事件时间,然后发送出去final long newTimestamp = userFunction.extractTimestamp(element.getValue(),

element.hasTimestamp() ? element.getTimestamp() : Long.MIN_VALUE);

output.collect(element.replace(element.getValue(), newTimestamp));

}

上面的processElement 方法,就是从用户代码中获取时间,然后注册到element中,输出到下游。

上面我们就分析了flink中的两种水印。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值