Window|青训营笔记

119 阅读4分钟

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

本次笔记重点内容

    1. 介绍三种最基本的window类型,以及他们的实现原理,结合业务场景介绍一些高级优化的功能和原理
    1. 结合两个真实业务场景的需求,讲解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

先攒一小批数据:image.png 若每个算子内部自己攒一个小的batch,如果上下游串联的算子比较多,任务整体的延迟就会影响结果。所以要通过watermark事件来作为mini-batch划分的依据,这样整个任务中不管串联的多少个算子,整个任务的延迟都是一样的,比较好控制。解决了中间结果偏多,状态访问频繁的问题

local-global

image.png 如同样颜色的数据表示相同的group by的key,这样我们可以在shuffle前的local agg阶段对他们做一个预聚合,然后到了global阶段数据倾斜就消除了

Distinct计算状态复用

image.png 把相同字段的distinct计算用一个map的key来存储,在map的value中,用一个bit vector(1/0表征来/没来过)就可以把各个状态复用到一起了。降低了状态量。

Pane优化

image.png 将窗口的状态划分成更小的pane,如3h窗口1h滑动,可以把pane设置为1h,这样每来一条数据,我们就只更新这条数据对应的pane的结果;当窗口需要输出结果的时候,只需要将这个窗口对应的pane的结果临时merge起来。降低了滑动窗口的状态存储量。

案例分析

使用Flink SQL计算抖音每天用户活跃数量的曲线

通过窗口计算DAU(Daily Active User),即每天的去重活跃用户数,开一个EMIT实时输出,过程中通过两阶段聚合来把数据打散,完成第一阶段聚合,第二阶段聚合就对各个分桶的结果求和即可。

使用Flink SQL计算大数据任务的资源使用

通过会话窗口将数据划分到一个window中,再将结果求和即可。