流式计算中的 Window 计算笔记(二)| 青训营笔记

249 阅读5分钟

流式计算中的 Window 计算笔记(二)| 青训营笔记

这是我参与「第四届青训营 -大数据场」笔记创作活动的第6天

三、Window概述

1. window基本功能

  • window分类

    • tumble window 滚动窗口
    • sliding window 滑动窗口
    • session window 会话窗口
    • 其他window:全局window、count window、累计窗口等
  • window使用

image.png

1.1 tumble window 滚动窗口

image.png

  • 窗口划分:每个key单独划分;每条数据只属于一个窗口
  • 窗口触发:window结束时间到达时一次性触发
1.2 HOP Sliding window 滑动窗口

image.png

  • 窗口划分:每个key单独划分;每条数据可能属于多个窗口
  • 窗口触发:window结束时间到达时一次性触发
1.3 session window 会话窗口

image.png

  • 窗口划分:每个key单独划分;每条数据会单独划分一个窗口,如果window之间有交集,则对窗口进行merge;

    • session窗口划分是动态的,可能会与之前的窗口合并
  • 窗口触发:window结束时间到达时一次性触发

1.4 迟到数据处理
  • 迟到:一条数据到来后会用window assigner给它划分一个window,一般时间窗口是一个时间区间,如果划分出来的window end比当前的watermark小,说明这个窗口已经触发计算了,这条数据就是迟到数据。
  • 什么情况下会产生迟到数据:只有事件时间下才会有迟到的数据。
  • 迟到数据的默认处理:丢弃
1.4.1 allow lateness

需要设置一个允许迟到的时间。设置之后窗口正常计算结束后不会马上清理状态,而是会多保留allow lateness这么长的时间。在这段时间内如果还有数据到来则继续之前的状态进行计算。

  • 适用:DataStream、SQL
1.4.2 SideOutput 侧输出流

这种方式对迟到数据打一个tag,然后在dataStream上根据这个tag获取迟到数据流,然后业务层自行选择进行处理。

  • 适用于 DataStream
1.5 增量计算和全量计算
  • 增量计算:每条数据到来直接进行计算

    • window只存储计算结果,不保留每条数据
    • 典型的reduce、aggregate等函数都是增量计算
    • SQL中聚合只有增量计算
  • 全量计算:每条数据到来后会存储到window的state中

    • window存储所有数据,触发计算时将所有数据拿出一起计算
    • 典型的process函数就是全量计算
1.6 EMIT触发
1.6.1 什么是EMIT
  • 通常window都是在结束时才输出结果。如果窗口比较大则计算结果输出的延迟就比较高,失去了实时计算的含义。
  • EMIT输出指的是在window没有结束时提前把window计算的部分结果输出出来。
1.6.2 怎么实现EMIT
  • DataStream中通过自定义Trigger来实现

    • Trigger的结果可以是

      • CONTINUE
      • FIRE(触发计算但不清理)
      • PURGE
      • FIRE_AND_PURGE
  • SQL通过配置:

    • table.exec.emit.early-fire.enabled=true
    • table.exec.emit.early-fire.delay=(time)
1.7 window offset

windowStart = timeStamp - (timeStamp - offset + windowSize)% windowSize

可以在计算窗口时让窗口有一个偏移。

  • DataStream支持offset,SQL不支持。
1.8 小结
  • 三种(滚动、滑动、会话)窗口的定义
  • 迟到数据处理:AllowLateness、SideOutput
  • 增量计算和全量计算模型
  • EMIT触发提前输出窗口的结果

2. window高级优化

2.1 mini-batch优化
  • RETRACT机制下中间结果偏多输出量大,内存存储到外部状态需要序列化和反序列化消耗CPU
  • 多条数据进行一次状态读取、序列化和反序列化、以及写入过程 (攒一批数据然后输出)
  • 上下游算子如果都缓存一批进行输出,数据延迟会大大增加
  • 利用类watermark传递机制,上游添加mini-batch assigner算子,发送开始mini-batch的信号;下游收到信号后开始对缓存数据进行计算,同时向下游继续发送;
2.2 local-global 倾斜优化
  • 在shuffle之前,先进行local预聚合,再shuffle到下游全局算子,解决数据倾斜的热点问题
2.3 distinct状态复用

image.png

  • DISTINCT通常优化为Group by等形式
  • 利用FILTER前置过滤DISTINCT
  • 复用DISTINCT,把key对应为bit value来确定状态(是否有对应key),从而通过filter复用;
  • 降低DISTINCT连续数据的存储量。
2.4 滑动窗口pane复用
  • 滑动窗口每条数据参与多个窗口,数据开销比较大
  • 把滑动窗口划分成更小的pane,从而变成类滚动窗口的形式;每个滑动窗口就是多个pane的聚合,从而数据在每个pane中可以节省访问,降低计算成本。
  • 输出时需要临时做一个默指。
2.5 小结
  • Mini-batch优化解决频繁访问状态的问题
  • local-global优化解决倾斜问题
  • Distinct状态复用降低状态量
  • Pane优化降低滑动窗口的状态存储量

四、案例分析

1. 计算抖音的日活曲线

所有数据都需要在一个subtask中完成窗口计算,无法并行。

SELECT
    SUM(partial_cnt) as dau
    TUMBLE_START(event_time, INTERVAL '1' DAY) as wstart,
    LOCALTIMESTAMP as current_ts
FROM(
    SELECT
        COUNT(DISTINCT uid) as partial_cnt,
        TUMBLE_ROWTIME(event_time, INTERVAL '1' DAY) as event_time
    FROM user_activity
    GROUP BY
    TUMBLE(event_time, INTERVAL '1' DAY),
    MOD(uid,10000-- 根据uid分为10000个桶
)
GROUP BY TUMBLE(event_time, INTERVAL '1' DAY)

通过两阶段聚合来把数据打散,完成第一轮聚合,第二轮聚合只需要对各个分桶的结果求和即可。

2. 计算大数据任务的资源使用

根据YARN上报的各个container的信息,在任务结束时尽快计算出一个任务占据的总资源,假设前后两个container间隔时间不足10min;

  • 典型通过会话窗口将数据划分到一个window中 然后将结果求和
SELECT application_id,
    SUM(cpu_usage) as CPU_TOTAL
    SUM(memory_usage) as MEMORY_TOTAL
FROM resource_usage
GROUP BY 
    application_id,
    SESSION(event_time, INTERVAL '10' MINUTE)

课程总结

  • 第一部分介绍了流式计算基本概念,以及和批式计算的区别
  • 第二部分介绍了watermark的含义、如何生成、如何传递,以及如何处理部分partition断流的问题
  • 第三部分介绍了三种基本的window的定义,以及迟到数据处理、增量计算VS全量计算、EMIT输出;同时也介绍了local-global优化、mini-batch优化、distinct状态优化、滑动窗口的pane的优化等
  • 两个案例介绍滚动窗口、会话窗口,以及两阶段聚合解决倾斜问题