为什么需要引入水位线(watermark)?

case 1: 消息到达没有延迟(理想情况)基于处理时间

  如图,假设数据源生成3条消息,分别是第13秒,第13秒,第16秒。计算窗口为10秒,每隔5秒滑动一次。

flink 水位线 窗口触发机制 flink水位线作用_延迟时间

这些消息在图4中会落入对应时间窗口。前两个在第13秒生成的消息会落入 [5s - 15s] 的窗口1和 [10s - 20s] 的窗口2。而第16秒生成的消息 会落入 [10s - 20s] 的窗口2和 [15s - 25s] 的窗口3。最终每隔窗口期望得到的结果分别是 (a,2), (a,3) 和 (a,1)。

case 2: 消息到达存在延迟 (基于处理时间)

假设有一个第13秒生成的消息到达时,延迟了6秒(在第19秒到达),原因可能是网络阻塞。那么情况就变成了图5这样。

flink 水位线 窗口触发机制 flink水位线作用_时间处理_02

第一个和第三个窗口的计算结果是产生误差了,未达到预期结果

case 3:用基于 event-time 的系统来处理问题

flink 水位线 窗口触发机制 flink水位线作用_时间处理_03

case 4:使用 Watermark 机制

告诉Flink 一个消息可以延迟多久

flink 水位线 窗口触发机制 flink水位线作用_flink 水位线 窗口触发机制_04


flink 水位线 窗口触发机制 flink水位线作用_flink 水位线 窗口触发机制_05

总结:
基于处理时间处理,如果第一个13秒数据会处于[5,15],[10,20]的窗口,第二个13秒因为延迟落入[10,20],[15-25],16秒数据落入[10,20],[15,25]
基于事件时间,不添加水位线,第一个13秒的事件时间是13秒,则处于[5,15],[10,20],第二个13秒的事件时间也为13,因此它的窗口应该为[10,20],为什么不是[15,25]因为事件时间为13<15
基于事件时间的水位线,相当于给定一个水位线,允许数据可以有一定延迟,则19秒的数据事件时间为13,则如果是一个延迟水位线5秒,则在水位线

水印=输入Flink的最大事件时间(mxtEventTime)-指定的延迟时间(t)
那么有Watermark的Window是怎么触发窗口函数的呢?
如果有窗户的停止时间等于或小于maxEventTime-t(当时的warkmark),那么这个窗户就被触发执行。

再举个简单的例子
需求:每3秒做一次滚动计算,统计窗口内的数据个数,最多延迟3秒。事件时间为eventtime
数据(以10点10分~10点11分的数据为例)
3,1,2,4,5,6
当3到来时:开辟一个1~3秒的一个窗口,水位为0
当1到来时,进入1~3秒的窗口,水位0
当2到来,同上
当4到来时,开辟4~-6的窗口。水位1
当5到来,进入4~6窗口,水位2
当6到来,进入4~6窗口,水位3,此时水位3>= 1~3的窗口的结束时间(3),触发1~3的窗口计算,结束后清空窗口数据,
如果后续再来1~3之间的数据,则根据设置的迟到数据策略进行处理(默认是丢弃的),因为当前最大水位时间已经超过3,代表不会再有小于3的事件数据进入
1-3秒的窗口数据:3,1,2
4-6的窗口数据:4,5,6

总结,窗口是Flink预先分配好的,不与数据到来的时间有关,如3秒窗口,flink一开始就会切成1~3,4~6·,7~9的窗口

如果窗口不触发运算,则窗口内的数据会一直保留