-
WaterMark是什么?
在了解Flink的WaterMark之前先要了解Flink的时间语义。在Flink里面有三种时间语义:
①Even Time:事件创建的时间,时间在数据里面。
②Ingestion Time:数据进入Flink的时间。
③Processing Time:处理数据的本地系统时间。
由于网络或者分布式系统的原因,在进入Flink的数据里面有的数据是乱序的,如果乱序了,要有一种机制来防止乱序数据影响到数据的最后处理结果,那么WaterMark就是避免乱序数据带来的计算不正确的。
WaterMark是一条特殊的数据,它有一个值,比如设定了延迟是一分钟,先在WaterMark已经涨到了10:00了,说明10:00以前的数据都已经到齐了,9:59分的数据就可以发车了。WaterMark必须是单调递增的,它与数据的时间戳有关。
下面通过图示来介绍WAaterMark的传递:
如图所示,在Flink的任务中有四个并行的子任务,它们初始的WaterMark分别是2,4,3,6,然后第一个子任务的WaterMark为4的数据来着,到达之后就更新自己的WaterMak变成4,那么就说明这个子任务的4之前的数据都到了,其他子任务也是一样。 -
WaterMark的引入和设定
引入watermark只需要在数据流里添加一个方法即可:
.assignAscendingTimestamps(_.timestamp * 1000)//设定每一条数据的timestamp为水位线
参数是指定数据里面的某一列作为watermark,也可以直接写一个数,不过一般不这么干,因为watermark是一直涨的,如果把参数写死了就说明生成的watermark是一样的,默认是200ms调用一次这个方法。除了上述方法还可以在参数里面传一个函数进去。如果是自定义函数的话就必须实现AssignerWithPeriodicWatermarks或者AssignerWithPunctuatedWatermarks,第一个是周期性生成watermark,后者则是断点式生成watermark。他们都必须实现的方法如下:
他们各自的两个方法功能其实是一样的,第一个就是生成watermark的方法,第二个就是提取时间戳;区别在于生成watermark的方法不一样,第一个是默认每个200ms调用一次生成watermark的方法,而第二个则是要自己定义什么时候生成,具体怎么实现就要看自己怎么用。