1. watermark定义
watermark是一种特殊的时间戳,用于表示eventTime小于watermark的事件已经全部落入到相应的窗口中,此时可进行窗口操作。
2. watermarks类型
- 有序流的watermarks
- 无序的流的watermarks
- 多并行流的watermarks
注意:多并行度的情况下,watermark对齐会取所有channel最小的watermark
3. watermark生成时机
通常,在接收到source的数据后,应该立刻生成watermark;但是,也可以在source后应用简单的map或者filter操作,再生成watermark。
4. watermark生成方式
- With Periodic Watermarks(常用):周期性(一定时间间隔或者达到一定的记录条数)生成watermark
- 需要实现AssignerWithPeriodicWatermarks接口
- 默认周期是200ms,可通过env.getConfig.setAutoWatermarkInterval进行修改
- 实际生产环境用得多,但必须结合时间或者累计条数两个维度,否则在极端情况下会有很大的延时
- With Punctuated Watermarks(不常用):在满足自定义条件时生成watermark,每一个元素都有机会判断是否生成一个watermark。
- 需要实现AssignerWithPunctuatedWatermarks接口
- 在
TPS
很高的生产环境下会产生大量的Watermark
,可能在一定程度上对下游算子造成一定的压力,只有在实时性很高的场景才会选择这种方式来进行生成水印
5. 更新规则
- 单并行度:watermark单调递增,一直覆盖较小的watermark
- 多并行度:每个分区都会维护和更新自己的watermark。某一时刻的watermark取所有分区中最小的那一个
6. 最大乱序时间
watermark的计算公式:
watermark = currentMaxTimestamp - maxOutOfOrderness
maxOutOfOrderness通过构造函数传入,如何设置maxOutOfOrderness才会比较合理呢?
- 如果maxOutOfOrderness设置的太小,而自身数据发送时由于网络等原因导致乱序或者延迟太多,那么最终的结果就是会有很多单条的数据在window中被触发,数据的正确性太差,容错性太低。
- 如果maxOutOfOrderness延时设置太大,则当大部分时间都已落入所属窗口时,flink迟迟不会进行窗口计算,影响数据的实时性;且由于在最大时间与watermark之间维护了很多未被触发的窗口,会加重Flink作业的负担。
- 总结:要结合自己的业务以及数据情况去设置。不是对eventTime要求特别严格的数据,不要采用eventTime方式来处理,会有丢数据的风险。
7. 迟到事件处理
迟到事件出现时窗口已经关闭并产出了计算结果,有三种处理方式
- 直接丢弃:将迟到事件视为错误消息并丢弃(flink默认处理方式)。
Side Output
机制:
可以将迟到事件单独放入一个数据流分支,这会作为 window 计算结果的副产品,以便用户获取并对其进行特殊处理。- Allowed Lateness机制:允许用户设置一个允许的最大迟到时长。Flink 会再窗口关闭后一直保存窗口的状态直至超过允许迟到时长,这期间的迟到事件不会被丢弃,而是默认会触发窗口重新计算。因为保存窗口状态需要额外内存,并且如果窗口计算使用了 ProcessWindowFunction API 还可能使得每个迟到事件触发一次窗口的全量计算,代价比较大,所以允许迟到时长不宜设得太长,迟到事件也不宜过多,否则应该考虑降低水位线提高的速度或者调整算法。
8. 未来事件处理
如果使用EventTime,有可能出现EventTime比当前时间还大的情况,这样Watermark会直接推到了未来某个时间点,导致这笔错误数据到达后的数据,到未来时间点之前的数据会被丢弃。
出现未来时间的数据,这本身是业务自身问题,上报了错误数据,一般两种方案:
- 将直接丢弃
- 设置最大超前时间,比如5分钟,超过5分钟丢弃