本文用于更新window机制相关内容,长期保持更新(细数踩过的坑)
1.flink window 时间机制
flink 时间window靠的是timestamp,不管是event time还是process time
我们都知道flink window开启一个时间的窗口用于接收数据,如事件时间
flink window 开启一定范围的窗口,ts1 to ts2 左闭右开
当数据的时间戳超过watermark( ts - delay >= ts2),该窗口计算关闭,开启下一个窗口(如果窗口大小是一分钟,ts 比ts2大一年,也是开启一个新窗口来计算该ts,中间是没有其他窗口的,虽然超过一年)
但是ts1和ts2到底是多少呢?也就是窗口开始和结束时间到底是怎么样的?
在org.apache.flink.streaming.api.windowing.windows.TimeWindow.java中有个方法
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
return timestamp - (timestamp - offset + windowSize) % windowSize;
}
看名字就知道getWindowStartWithOffset,获取window开始的偏移量,那就是开始时间咯
startTime=timestamp - (timestamp - offset + windowSize) % windowSize
offset是时区偏移量windowSize%windowSize=0
所以上述公式可以转换为
startTime=timestamp - timestamp % windowSize
举个例子
最开始有条数据入窗口,时间戳是1661097226000对应北京时间2022-8-21 23:53:46
如果windowSize是1min,也就是60000
startTime = 1661097226000- 1661097226000% 60000
startTime = 1661097226000-46000=1661097180000=北京时间2022-8-21 23:53:00
也就是1min窗口,会从第一条数据的事件时间的分钟头开始计算,例如23:53:46 window开始时间为23:53:00,结束时间为23:54:00
同样,秒级窗口也一样23:53:46:123 窗口开始时间为23:53:46,结束时间为23:53:47(23:53:46+windowSize秒)
机制下可能造成的数据错乱问题
那么问题来了,flink该方法时间戳与window毫秒级数值进行运算,如果你的时间戳10(秒级别),会造成数据错乱,例如5秒窗口
1661097226 - 1661097226%5000 =1661097226 - 2226=1661095000 对应北京时间2022-8-21 23:16:40,(芜湖起飞,数据错乱,所以你遇到10位时间戳需要补000,血与泪的教训)