上一节的案例我们得到了触发window的条件
watermark+window 处理乱序数据
我们上面的测试,数据都是按照时间顺序递增的,现在,我们输入一些乱序的(late)数据,
看看 watermark 结合 window 机制,是如何处理乱序的。
nc -l 9000
0001,1538359882000
0001,1538359886000
0001,1538359892000
0001,1538359893000
0001,1538359894000
0001,1538359896000
0001,1538359899000
0001,1538359891000
Key |
Event Time |
CurrentMaxTim eStamp |
WaterMark |
window_start_ time |
window_end_t ime |
0001 |
|
|
| ||
2018-10-01 10:11:22.000 |
2018-10-01 10:11:22.000 |
2018-10-01 10:11:12.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:26.000 |
2018-10-01 10:11:26.000 |
2018-10-01 10:11:16.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:32.000 |
2018-10-01 10:11:32.000 |
2018-10-01 10:11:22.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:33.000 |
2018-10-01 10:11:33.000 |
2018-10-01 10:11:23.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:34.000 |
2018-10-01 10:11:34.000 |
2018-10-01 10:11:24.000 |
[10:11:21.000 |
10:11:24.000) | |
0001 |
|
|
| ||
2018-10-01 10:11:36.000 |
2018-10-01 10:11:36.000 |
2018-10-01 10:11:26.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:37.000 |
2018-10-01 10:11:37.000 |
2018-10-01 10:11:27.000 |
[10:11:24.000 |
10:11:27.000) | |
0001 |
|
|
| ||
2018-10-01 10:11:39.000 |
2018-10-01 10:11:39.000 |
2018-10-01 10:11:29.000 |
0001 |
|
|
| ||
2018-10-01 10:11:31.000 |
2018-10-01 10:11:39.000 |
2018-10-01 10:11:29.000 |
可以看到,虽然我们输入了一个 10:11:31 的数据,但是 currentMaxTimestamp 和 watermark 都没变。此时,按照我们上面提到的公式:
watermark 时间(10:11:29) < window_end_time(10:11:33),因此不能触发 window。
那如果我们再次输入一条 10:11:43 的数据,此时 watermark 时间会升高到 10:11:33,这时的 window 一定就会触发了,我们试一试:
输入:
nc -l 9000
0001,1538359882000
0001,1538359886000
0001,1538359892000
0001,1538359893000
0001,1538359894000
0001,1538359896000
0001,1538359899000
0001,1538359891000
0001,1538359893000
汇总信息就不写了
关于late element(延迟数据)的处理
延迟数据三种处理方案
丢弃(默认)
我们输入一个乱序很多的(其实只要 Event Time < watermark 时间)数据来测试下: 输入:
nc -l 9000
0001,1538359890000
0001,1538359903000
注意:此时 watermark 是 2018-10-01 10:11:33.000 下面我们再输入几个 eventtime 小于 watermark 的时间
在输入
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
注意:此时并没有触发 window。因为输入的数据所在的窗口已经执行过了,flink 默认对这 些迟到的数据的处理方案就是丢弃。
allowedLateness 指定允许数据延迟的时间
在某些情况下,我们希望对迟到的数据再提供一个宽容的时间。
Flink 提供了 allowedLateness 方法可以实现对迟到的数据设置一个延迟时间,在指定延迟时 间内到达的数据还是可以触发 window 执行的。
下面我们来验证一下:
输入:【输入两行内容】
nc -l 9000
0001,1538359890000
0001,1538359903000
正常触发 window,没什么问题。 汇总:
Key |
Event Time |
CurrentMaxTim eStamp |
WaterMark |
window_start_ time |
window_end_t ime |
0001 |
|
|
| ||
2018-10-01 10:11:30.000 |
2018-10-01 10:11:30.000 |
2018-10-01 10:11:20.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:43.000 |
2018-10-01 10:11:43.000 |
2018-10-01 10:11:33.000 |
[10:11:33.000 |
10:11:33.000) |
此时 watermark 是 2018-10-01 10:11:33.000 那么现在我们输入几条 eventtime<watermark 的数据验证一下效果
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
在这里看到每条数据都触发了 window 执行。 汇总:
Key |
Event Time |
CurrentMaxTim eStamp |
WaterMark |
window_start_ time |
window_end_t ime |
0001 |
|
|
| ||
2018-10-01 10:11:30.000 |
2018-10-01 10:11:30.000 |
2018-10-01 10:11:20.000 | |||
0001 |
|
|
| ||
2018-10-01 10:11:43.000 |
2018-10-01 10:11:43.000 |
2018-10-01 10:11:33.000 |
[10:11:33.000 |
10:11:33.000) | |
0001 |
|
|
| ||
2018-10-01 10:11:30.000 |
2018-10-01 10:11:43.000 |
2018-10-01 10:11:33.000 |
[10:11:33.000 |
10:11:33.000) | |
0001 |
|
|
| ||
2018-10-01 10:11:31.000 |
2018-10-01 10:11:43.000 |
2018-10-01 10:11:33.000 |
[10:11:33.000 |
10:11:33.000) | |
0001 |
|
|
| ||
2018-10-01 10:11:32.000 |
2018-10-01 10:11:43.000 |
2018-10-01 10:11:33.000 |
[10:11:33.000 |
10:11:33.000) |
我们再输入一条数据,把 water 调整到 10:11:34 输入:
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
0001,1538359894000
此时,把 water 上升到了 10:11:34,我们再输入几条 eventtime<watermark 的数据验证一下
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
0001,1538359894000
0001,1538359890000
0001,1538359891000
0001,1538359892000
发现输入的三行数据都触发了 window 的执行。
我们再输入一条数据,把 water 调整到 10:11:35
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
0001,1538359894000
0001,1538359890000
0001,1538359891000
0001,1538359895000
此时,watermark 上升到了 10:11:35
我们再输入几条 eventtime<watermark 的数据验证一下效果
nc -l 9000
0001,1538359890000
0001,1538359903000
0001,1538359890000
0001,1538359891000
0001,1538359892000
0001,1538359894000
0001,1538359890000
0001,1538359891000
0001,1538359895000
0001,1538359890000
0001,1538359891000
0001,1538359892000
发现这几条数据都没有触发 window。
分析:
当 watemark 等于 10:11:33 的时候,正好是 window_end_time,所以会触发[10:11:30~10:11:33) 的 window 执行。
当窗口执行过后,我们输入[10:11:30~10:11:33) window 内的数据会发现 window 是可以被触 发的。
当 watemark 提升到 10:11:34 的时候,我们输入[10:11:30~10:11:33)window 内的数据会发现 window 也是可以被触发的。
当 watemark 提升到 10:11:35 的时候,我们输入[10:11:30~10:11:33)window 内的数据会发现 window 不会被触发了。
由于我们在前面设置了 allowedLateness(Time.seconds(2)),可以允许延迟在 2s 内的数据继续 触发 window 执行。
所以当 watermark 是 10:11:34 的时候可以触发 window,但是 10:11:35 的时候就不行了。
总结:
对于此窗口而言,允许 2 秒的迟到数据,即第一次触发是在 watermark >=window_end_time 时
第二次(或多次)触发的条件是 watermark < window_end_time + allowedLateness 时间内, 这个窗口有 late 数据到达时。
解释:
当 watermark 等于 10:11:34 的时候,我们输入 eventtime 为 10:11:30、10:11:31、10:11:32 的 数据的时候,是可以触发的,因为这些数据的 window_end_time 都是 10:11:33,也就是 10:11:34<10:11:33+2 为 true。
但是当 watermark 等于 10:11:35 的时候,我们再输入 eventtime 为 10:11:30、10:11:31、10:11:32 的数据的时候,这些数据的 window_end_time 都是 10:11:33,此时,10:11:35<10:11:33+2 为 false 了。所以最终这些数据迟到的时间太久了,就不会再触发 window 执行了。
第三种策略:
sideOutputLateData 收集迟到的数据
通过 sideOutputLateData 可以把迟到的数据统一收集,统一存储,方便后期排查问题
此时,针对这几条迟到的数据,都通过 sideOutputLateData 保存到了 outputTag 中。
多并行度情况下的wartermark
改一下代码
输入如下几行内容:
0001,1538359882000
0001,1538359886000
0001,1538359892000
0001,1538359892000
0001,1538359894000
0001,1538359896000
0001,1538359897000
会发现 window 没有被触发。
因为此时,这 7 条数据都是被不同的线程处理的。每个线程都有一个 watermark。
因为在多并行度的情况下,watermark 对齐会取所有 channel 最小的 watermark 但是我们现在默认有 8 个并行度,这 7 条数据都被不同的线程所处理,到现在还没获取到最 小的 watermark,所以 window 无法被触发执行。
下面我们来验证一下,把代码中的并行度调整为 2.
输入如下几行内容:
0001,1538359890000
0001,1538359903000
0001,1538359908000
此时会发现,当第三条数据输入完以后,[10:11:30,10:11:33)这个 window 被触发了。 前两条数据输入之后,获取到的最小 watermark 是 10:11:20,这个时候对应的 window 中没 有数据。
第三条数据输入之后,获取到的最小 watermark 是 10:11:33,这个时候对应的窗口就是 [10:11:30,10:11:33)。所以就触发了。
Flink应该如何设置最大乱序时间
•这个要结合自己的业务以及数据情况去设置。如果maxOutOfOrderness设置的太小,而自身数据发送时由于网络等原因导致乱序或者late太多,那么最终的结果就是会有很多单条的数据在window中被触发,数据的正确性影响太大
•对于严重乱序的数据,需要严格统计数据最大延迟时间,才能保证计算的数据准确,延时设置太小会影响数据准确性,延时设置太大不仅影响数据的实时性,更加会加重Flink作业的负担,不是对eventTime要求特别严格的数据,尽量不要采用eventTime方式来处理,会有丢数据的风险。