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

91 阅读6分钟

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

流式计算中的 Window 计算

  • 了解实时计算和批式计算的本质区别,以及实时计算所带来的新的机遇和挑战
  • 了解实时计算中的核心功能: Watermark 机制、 Window 机制
  • 了解3大基本窗口类型的定义、使用以及核心原理
  • 了解窗口机制中的最核心的优化及其原理

概述

1. 流式计算vs批式计算

1.jpg

数据价值:实时性越高,数据价值越高

2. 批处理

  • 批处理模型典型的数仓为T+1架构,即数据计算是天级别的,当天只能看到前一天的计算结果。
  • 通常使用的计算引擎为Hive或者Spark等。计算的时候,数据是完全ready的,输入和输出都是确定性的

3. 小时级批计算

如何做到更实时?

  • 实时计算:处理时间窗口
  • 数据实时流动,实时计算,窗口结束直接发送结果,不需要周期调度任务。

4. 处理时间vs事件时间

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

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

处理时间要比事件时间有一定延迟

5. 事件时间窗口

1.jpg

  • 实时计算:事件时间窗口

  • 数据实时进入到真实事件发生的窗口中进行计算,可以有效地处理数据延迟和乱序

窗口什么时候算结束? 引出Watermark

6. Watermark

  • 在数据中插入—些watermark,来表示当前的真实时间。

  • 在w(11)之后,有比11更小的数据,就认为时延迟数据,不应该参与前面的计算 1.jpg

  • 在数据存在乱序的时候,watermark就比较重要了,它可以用来在乱序容忍和实时性之间做一个平衡

  • w(11)左边没有更小的数据,有更小的数据,则是一个迟到的数据,前面的窗口已经算过了

0686474b01879c6beedd9f1ccf4de93.png

小结:

  1. 批式计算一般是 T +1的数仓架构

  2. 数据实时性越高,数据的价值越高

  3. 实时计算分为处理时间和事件时间

  4. 事件时间需要 Watermark 配合来处理乱序

Watermark

Watermark定义:当前系统认为的事件时间所在的真实时间(机器时间)

1. 传递Watermark

1.jpg

  • 三个task:source,map,window。
  • source的watermark传递给下游,下游收到之前watermark是29,是一对一传递。
  • 多对多传递,window会取收到的最小值,作为watermark

2. 观察一个任务中的watermark量

问题:为什么开发了window有数据输入没有数据输出? 首先怀疑watermark是否是正常的

3. Per-partition / Per-subtask 生成watermark

  • 在Flink里早期都是per-subtask的方式进行watermark的生成
  • 如果每个source task如果有消费多个partition的情况的话,那多个partition之间的数据可能会因为消费的速度不同而最终导致数据的乱序程度增加。

4. 部分partition/subtask断流

(有时候是业务数据本身就有这种特点,比如白天有数据,晚上没有数据。) watermark默认是不会更新的,因为它要取上游subtask发来的最小值。

解决方案:Idle source

当断流超过配置的idle超时时间时,将当前subtask标记为idle,并发给下游。下游在计算自身watermark的时候,可以忽略掉当前是idle的那些subtask

5. 时间晚于watermark的数据的处理

晚于watermark的数据

  • window聚合,默认就是丢弃
  • 双流join,可以认为是无法与之前正常数据join上
  • CEP,默认就是丢弃

6. 小结

  1. 含义:表示系统认为的当前真实时间

  2. 生成:可以通过 Watermark Generator 来生成

  3. 传递:取上游所有 subtask 的最小值

  4. 部分数据断流: ldle Source

  5. 迟到数据处理: Window 算子是丢弃; Join 算子认为跟之前的数据无法 join 到

Window

1. 基本功能

1. window分类

典型的Window:

  • Tumble Window(滚动窗口)
  • Sliding Window(滑动窗口)
  • Session Window(会话窗口)

其它Window:

  • 全局Window
  • Count Window
  • 累计窗口等

2. window使用

API应用程序编程接口,抽象分层

层次越高,抽象程度越高,用户使用成本低,表达能力低(有限)

3. 滚动窗口

  • 窗口划分:
  1. 每个key单独划分
  2. 每条数据只会属于一个窗口
  • 窗口触发 Window结束时间到达的时候一次性触发

1.jpg

4. 滑动窗口

  • 窗口划分:
  1. 每个key单独划分
  2. 每条数据可能会属于多个窗口
  • 窗口触发: Window结束时间到达的时候一次性触发

1.jpg

5. 会话窗口

  • 窗口划分:
  1. 每个key单独划分
  2. 每条数据会单独划分为一个窗口,如果window之间有交集,则会对窗口进行merge
  • 窗口触发: Window结束时间到达的时候一次性触发

上面两个窗口的划分,都是根据当前数据的时间就可以直接确定它所属的窗口,会话窗口不能直接确定它所属的窗口(窗口划分是一个动态过程,可能窗口合并)

1.jpg

6. 迟到数据处理

只有事件时间,实际时间下才会有迟到的数据;

处理时间(系统观测,理论时间)不产生

迟到数据默认处理?丢弃

  1. Allow lateness

需要设置一个允许迟到的时间,会应用到retract机制

  1. SideOutput(侧输出流)

对迟到数据打一个tag

7. 窗口计算模型

  • 增量计算: 来一条就计算一条

典型的reduce、aggregate等级函数都是增量计算

SQL的聚合只有增量计算

  • 全量计算: 先缓存,在一起计算

典型的process函数就是全量计算

8. EMIT触发

EMIT 输出指的是:在 window 没有结束的时候,提前把 window 计算的部分结果输出出来

实现:

  1. 在DataStream里可以通过自定义Trigger来实现:
  • CONTIUNE
  • FIRE(触发计算,但是不清理)
  • PURGE
  • FIRE_AND_PURGE
  1. SQL也可以使用

9. 小结

  1. 三种(滚动、滑动、会话)窗口的定义

  2. 迟到数据处理: AllowLateness 、SideOutput

  3. 增量计算和全量计算模型

  4. EMIT 触发提前输出窗口的结果

2. 高级优化

Mini-batch

优化解决频繁访问状态的问题

1.jpg

Local-global

local-global优化是分布式系统中典型的优化,主要是可以降低数据shuffle的量,同时也可以缓解数据的倾斜 1.jpg

Distinct 计算状态复用

1.jpg

Pane 优化

1.jpg

小结

  1. Mini - batch 优化解决频繁访问状态的问题

  2. local - global 优化解决倾斜问题

  3. Distinct 状态复用降低状态量

  4. Pane 优化降低滑动窗口的状态存储量

案例分析

1. 使用Flink SQL 计算抖音的日活曲线 DAU

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