这是我参与「第四届青训营 」笔记创作活动的第四天
数据实时流动,实时计算时间窗口,窗口结束后直接发送结果,不需要周期调度任务。 那么这里的时间指的是处理时间还是事件时间呢?
处理时间:数据在流式计算系统中真正处理时所在机器的当前时间。
事件时间:数据产生的时间,比如客户端、传感器、后端代码等上报数据时的时间
在Flink中,默认是事件时间。
Watermark
那么在Flink中,时间的概念是怎么实现的?
Flink在数据中插入一些Watermark,来表示系统认为的当前真实的事件时间
Watermark在Flink中尤为重要,因为在分布式的场景下,数据的处理是存在乱序的,它可以用来在乱序容忍和实时性之间做一个平衡。
简单来说,司机(Flink)自己是没表的,但是他根据上车的乘客(数据)身上带的时间来判断。
那么如何传递Watermark呢?
下游算子取上游所有subtask的最小值
同时上游算子也有标志告诉下游算子现在是几点,这样的话,下游算计就不依赖上游算子的结果输出了(上游算子还在等呢)。
具体实现上,水位线可以看作一条特殊的数据记录,插入到数据流中的一个标记点,主要内容就是一个时间戳。
但是也不是来一个数据就生成一个水位线,这样的话如果数据量很大的话是很没有效率的,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. 每条数据只会属于一个窗口
滑动窗口
1.用两个参数定义:window size, window slide。窗口大小表示处理的数据量,滑动步长表示计算频次
2.每个key单独划分
- 当滑动步长小于窗口大小时,滑动窗口就会出现重叠,这时数据也可能会被同时分配到多个窗口中。
会话窗口
- 只能基于时间来定义。最重要的参数就是会话的超时时间,也就是两个会话窗口之间的最小距离。涉及到乱序,窗口可能还需要合并
2.每个key单独划分
3.每条数据会单独划分为一个窗口,如果window之间有交集,则会对窗口进行merge
全局窗口
这种窗口全局有效, 会把相同key的所有数据都分配到同一个窗口中。这种窗口没有结束时,默认是不会触发计算的。如果希望它能对数据进行计算处理,还需要自定义Trigger。
Flink中的计数窗口,底层就是用全局窗口实现的。
Window的意义:窗口的设置提高了计算资源的利用率。 假设你想计算一个月的月活,那么你不需要等到一个月以后,再将整一个月的数据进行计算,而是采用流式计算。因为在期间一个月攒数据的过程中,流式计算已经在算了。一个个窗口将无界的数据流分成有界的数据块,提高了资源利用的效率,因此节省了时间。