flink watermark

flink1.12版本开始,事件事件作为默认的时间语义

watermark是flink逻辑时钟,不是真正意义上的表,而是靠着数据去推动它的时间不停的往前走

工厂生产的商品上面印有时间戳,八点到九点的商品要坐一班车运走,商品从生产到运上车中间有一定的时间间隔,班车不能以系统时间作为时间判断标准,而应该以商品上面自带的时间戳作为时间判断标准,八点十分的商品来了,班车认为现在时间到了八点十分,九点钟的商品来了,班车认为现在时间到了九点,那么班车就带着[8,9)的商品出发了
但是这样的话只有当前的班车知道现在时间是多少,后面的班车不知道现在时间(逻辑时间),那么后面的班车就不能进行时间相关的操作 应该有一个标志来指明当前数据流里面时钟到底是怎么样前进的,而且这些标志需要从前边的算子任务传递到后面的算子任务,即使当前窗口数据没有输出,也要把当前时钟的标志传递到下游,下游的任务就不用依赖数据里面的标签了

那么水位线就是用来指明当前逻辑时钟进展的标记 (毫秒数)

问题一:如果数据稀疏,来一个数据判断一下时间戳,插入对应的水位线,没问题
但是如果数据非常稠密,同一毫秒有海量的数据到来,这时候如果还每一条数据都判断时间戳,插入水位线,就做了大量的无用功
解决方法:周期性的生成水位线

flink自带的水位线生成方法中,生成水位线的时间间隔为200毫秒
@Override
public void onPeriodicEmit(WatermarkOutput output) {
// 发射水位线,默认 200ms 调用一次
output.emitWatermark(new Watermark(maxTs - delayTime - 1L));
}
我们在 onPeriodicEmit()里调用 output.emitWatermark(),就可以发出水位线了;这个方法由系统框架周期性地调用,默认 200ms 一次。
可以通过以下方法设置
env.getConfig().setAutoWatermarkInterval(1000L);
可以通过以下方法查看系统默认间隔
System.out.println(env.getConfig().getAutoWatermarkInterval());
也可以在源码中查看
在这里插入图片描述

问题二:数据是乱序的,比方说八点二十的数据已经到了,八点十分的数据才到,这时候再按照迟到的八点十分的数据生成水位线就倒退了,但是时间一定是单调递增的,时间是不能倒退的
解决方法:判断当前最新的时间戳是否比之前最大的时间戳要大,如果大的话,时间才朝前进展,如果小,那就是一个迟到数据,对时间的进展没有贡献
周期性生成水位线,保留之前所有数据中最大时间戳,需要插入水位线的时候,直接以它作为时间戳生成新的水位线

在水位线策略中的forBoundedOutOfOrderness方法里面的onEvent方法中,每个事件到来的时候都会做一次判断,maxTimestamp = Math.max(maxTimestamp, eventTimestamp);判断是否为最大的时间戳

问题三:如何处理迟到数据
解决方法:经验性的给一个延迟时间
两种方案:1.比方说[0-9)秒的窗口,给了2秒的延迟,那么等到11秒水位线生成的时候才发车 2.[0-9)秒的窗口,给了2秒的延迟,最大时间戳为9秒的时候,生成的水位线减两秒,最大时间戳为11秒的时候,生成的水位线减两秒,也就是九秒,刚好发车 两种处理方法是等价的,但是后面一种更好理解,所以我们选择后面一种

在处理乱序流的forBoundedOutOfOrderness()的参数中可以传Duration.ofSeconds(2)来标记需要水位线延迟几秒钟生成
在水位线生成方法onPeriodicEmit中可以看到
output.emitWatermark(new Watermark(maxTimestamp - outOfOrdernessMillis - 1));
最后-1毫秒表示包头不包尾

设置水位线离源越近越好

允许延迟
.allowedLateness(Time.minutes(1))

侧输出流
OutputTag<> outputTag = new OutputTag<>(“late”){};

.sideOutputLateData(outputTag)

生成水位线方法.assignTimestampAndWatermarks()中
参数为水位线策略WatermarkStrategy
水位线策略WatermarkStrategy中需要实现两个方法,
分别是createWatermarkGenerator水位线生成和createTimestampAssigner时间戳分配
调用forBoundedOutOfOrderness完成水位线生成
调用withTimestampAssigner完成时间戳分配

  • 示例

.assignTimestampsAndWatermarks(//分配时间戳和水位线
WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(2))//延迟两秒的乱序流水位线生成器
.withTimestampAssigner( (SerializableTimestampAssigner) (adData,recordTimestamp) -> adData.getTimestamp() )//序列化的时间戳分配器
);
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值