Watermark以及Window机制 | 青训营笔记

106 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第四天

数据实时流动,实时计算时间窗口,窗口结束后直接发送结果,不需要周期调度任务。 那么这里的时间指的是处理时间还是事件时间呢?

处理时间:数据在流式计算系统中真正处理时所在机器的当前时间。

事件时间:数据产生的时间,比如客户端、传感器、后端代码等上报数据时的时间

image.png

在Flink中,默认是事件时间。

Watermark

那么在Flink中,时间的概念是怎么实现的?

Flink在数据中插入一些Watermark,来表示系统认为的当前真实的事件时间

  image.png

Watermark在Flink中尤为重要,因为在分布式的场景下,数据的处理是存在乱序的,它可以用来在乱序容忍和实时性之间做一个平衡。

  image.png

简单来说,司机(Flink)自己是没表的,但是他根据上车的乘客(数据)身上带的时间来判断。

那么如何传递Watermark呢?

下游算子取上游所有subtask的最小值

同时上游算子也有标志告诉下游算子现在是几点,这样的话,下游算计就不依赖上游算子的结果输出了(上游算子还在等呢)。

  image.png

具体实现上,水位线可以看作一条特殊的数据记录,插入到数据流中的一个标记点,主要内容就是一个时间戳。

但是也不是来一个数据就生成一个水位线,这样的话如果数据量很大的话是很没有效率的,Flink的策略是是周期性地插入水位线

因为watermark表示当前事件发生的真实事件,那晚于watermark的数据到来时,系统会认为这种数据是迟到的数据。新的时间戳若是没有比之前的时间大,那么就是说它没有对推动时间做贡献,属于是迟到的数据,需要保存状态

Flink无法真正处理迟到的数据,你定了[0, 9)的窗口,但是后面可能来8,7的数据。

由算子自身来决定如何处理迟到数据:

  • Window聚合,默认会丢弃迟到数据

  • 双流join,如果是outer join,则可以认为它不能join到任何数据

  • CEP,默认丢弃

Window机制

在Flink中,窗口就是用来处理无界流的核心,将无限数据切割成有限的“数据块”进行处理,这就是所谓的window(窗口)。

按照它本来的时间戳判断它是否属于这个窗口,窗口不是一个框,而是一个桶。每个窗口会被映射成一个桶。 在Flink中,窗口可以把无限大小的流切割成有限打小的多个存储桶(bucket),每个数据都会分发到对应的桶中,当到达窗口结束时间时,就对每个桶中的数据进行计算处理。

窗口不是静态准备好的,而是动态创建的。

Watermark只是用来推动窗口的关闭,但不决定数据分到哪个窗口。

按照窗口分配数据的规则分类,可以把窗口分为

滚动窗口

1.  需要的参数只有一个,就是window size, 可以基于时间定义,也可以基于数据个数定义。

2.  每个key到哪都划分。

3.  每条数据只会属于一个窗口

image.png 滑动窗口

1.用两个参数定义:window size, window slide。窗口大小表示处理的数据量,滑动步长表示计算频次

2.每个key单独划分

  1. 当滑动步长小于窗口大小时,滑动窗口就会出现重叠,这时数据也可能会被同时分配到多个窗口中。

image.png  

会话窗口

  1. 只能基于时间来定义。最重要的参数就是会话的超时时间,也就是两个会话窗口之间的最小距离。涉及到乱序,窗口可能还需要合并

2.每个key单独划分

3.每条数据会单独划分为一个窗口,如果window之间有交集,则会对窗口进行merge

image.png

全局窗口

这种窗口全局有效, 会把相同key的所有数据都分配到同一个窗口中。这种窗口没有结束时,默认是不会触发计算的。如果希望它能对数据进行计算处理,还需要自定义Trigger。

Flink中的计数窗口,底层就是用全局窗口实现的。

Window的意义:窗口的设置提高了计算资源的利用率。 假设你想计算一个月的月活,那么你不需要等到一个月以后,再将整一个月的数据进行计算,而是采用流式计算。因为在期间一个月攒数据的过程中,流式计算已经在算了。一个个窗口将无界的数据流分成有界的数据块,提高了资源利用的效率,因此节省了时间。