这是我参与「第四届青训营 」笔记创作活动的第7天
本次笔记重点内容
-
- 介绍三种最基本的window类型,以及他们的实现原理,结合业务场景介绍一些高级优化的功能和原理
-
- 结合两个真实业务场景的需求,讲解window是如何解决实际生产问题的
Window分类
Tumble Window 滚动窗口
根据数据的时间(可以是处理时间,也可以是事件时间)划分到它所属的窗口中,每条数据只会落在一个窗口中
Sliding Window 滑动窗口
每条数据是可能会属于多个窗口的(具体属于多少,取决于窗口定义的大小和滑动)
Session Window 会话窗口
数据到来后不能确定属于哪个大小的窗口,就是说可能会跟别的已有窗口合并形成新的窗口,或者下一条数据来之后会改变这个数据的所在窗口,是动态的
实际问题
迟到数据处理
一条数据到来后,会给它划分一个时间区间作为窗口,如果window end比当前的watermar值还小,说明这个窗口已经被触发了,这条数据就被认为是迟到了。
- Allow latenes,设置一个允许迟到的时间,这段时间内有数据到来也可继续之前的状态进行计算
- SideOutput,对迟到数据打一个tag,在DataStream上根据这个tag获取迟到的数据流,再由用户自己来决定如何处理这部分数据
增量 VS 全量计算
增量计算就是每来一个数据就进行计算,状态中只存储结果;全量计算,每条数据到来会存储到window的state中,window触发计算时才将所有数据拿出来一起计算。
EMIT触发
正常的窗口都是窗口结束的时候才会进行输出,比如一个1天的窗口,只有到每天结束的时候,窗口的结果才会输出,这种情况下就失去了实时计算的意义。EMIT触发可以提前把窗口内容输出出来,比如我们可以配置一个1天的窗口,每隔5s输出一次它的最新结果,那这样下游就可以更快的获取到窗口计算的结果了。
Window高级优化
Mini-batch
先攒一小批数据:
若每个算子内部自己攒一个小的batch,如果上下游串联的算子比较多,任务整体的延迟就会影响结果。所以要通过watermark事件来作为mini-batch划分的依据,这样整个任务中不管串联的多少个算子,整个任务的延迟都是一样的,比较好控制。解决了中间结果偏多,状态访问频繁的问题
local-global
如同样颜色的数据表示相同的group by的key,这样我们可以在shuffle前的local agg阶段对他们做一个预聚合,然后到了global阶段数据倾斜就消除了。
Distinct计算状态复用
把相同字段的distinct计算用一个map的key来存储,在map的value中,用一个bit vector(1/0表征来/没来过)就可以把各个状态复用到一起了。降低了状态量。
Pane优化
将窗口的状态划分成更小的pane,如3h窗口1h滑动,可以把pane设置为1h,这样每来一条数据,我们就只更新这条数据对应的pane的结果;当窗口需要输出结果的时候,只需要将这个窗口对应的pane的结果临时merge起来。降低了滑动窗口的状态存储量。
案例分析
使用Flink SQL计算抖音每天用户活跃数量的曲线
通过窗口计算DAU(Daily Active User),即每天的去重活跃用户数,开一个EMIT实时输出,过程中通过两阶段聚合来把数据打散,完成第一阶段聚合,第二阶段聚合就对各个分桶的结果求和即可。
使用Flink SQL计算大数据任务的资源使用
通过会话窗口将数据划分到一个window中,再将结果求和即可。