流计算中的 window 计算 | 青训营笔记

76 阅读4分钟

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

1、 流计算概述

1.1 处理时间窗口

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

image.png

1.2 处理时间 VS 事件时间

  • 处理时间:数据在流式计算系统中真正处理时所在机器的当前时间
  • 事件时间:数据产生的时间,比如客户端、传感器、后端代码等上报数据时的时间

image.png

1.3 事件时间窗口

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

image.png

  • 窗口结束时间:没办法预知。故引出:Watermark

1.4 Watermark

  • 在数据中插入一些watermark,来表示当前的真实时间 image.png
  • 在数据乱序的时候,watermrk 比较重要,它可以用来在乱序容忍和实时性之间做一个平衡 image.png

2、 关于Watermark

2.1 Watermark了解

  • Watermark 表示当前真实的事件时间
  • 如何产生: image.png
  • 如何传递: image.png
  • 如何通过 Flink UI 观察 Watermark: image.png

2.2 典型问题

2.2.1 Per-partition VS per-subtask watermark 生成

-   Per-subtask watermark 生成

    -   早期版本都是这种机制。如果一个 source subtask 消费多个 partition,那么多个partition 直接按的数据读取可能会加剧乱序程度。

-   Per-partition watermark 生成

    -   新版本引入了基于每个 partition 单独的 watermark 生成机制,这种机制可以有效避免上面的问题。

2.2.2 部分 partition/subtask 断流

  • 根据上面提到的 watermark 传递机制,下游 subtask 会将上游所有 subtask 的 watermark 值的最小值作为自身的 watermark 值。如果上游有一个 subtask 的 watermark 的不更新了,则下游的 watermark 都不更新。

  • 解决方案:Idle source

    • 当某个 subtask 断流超过配置的 idle 超过时间时,将当前 subtask 设置为 idle,并下发一个 idle 的状态给下游。下游在计算自身 watermark 的时候,可以忽略掉当前是 idle 的那些 suatask。

2.2.3 迟到数据处理

  • 因为 watermark 表示当前事件发生的真实时间,那晚于 watermark 的数据到来时,系统会认为这种数据是迟到的数据。

  • 算子自身来决定如何处理迟到数据

    • Window 聚合:默认丢弃
    • 双流 JOIN:如果是 OUTER JOIN,则认为他不可能 JOIN 到任何数据
    • CEP:默认丢弃

3、 Window

3.1 基本功能

3.1.1 Window 分类

  • Tumble Window(滚动窗口)
    • 窗口划分:每个 key 单独划分;每条数据只属于一个窗口
    • 窗口触发:Window 结束时间到达的时候一次性触发

image.png

  • Sliding Window(滑动窗口)
    • 窗口划分:每个 key 单独划分;每条数据可能会属于多个窗口
    • 窗口触发:Window 结束时间到达的时候一次性触发

image.png

  • Session Window(会话窗口)
    • 窗口划分:每个 key 单独划分;每条数据会单独地划分一个窗口如果 Window 之间有交集,则会对窗口进行 merge
    • 窗口触发:Window 结束时间到达的时候一次性触发

image.png

3.1.2 数据迟到

  • 定义: image.png

  • 产生情况:只有事件时间下才会有迟到的数据

  • 默认处理:丢弃 image.png

  • 迟到数据处理:

    • Allow lateness:这种方式需要设置一个允许迟到的时间。设置之后,窗口正常计算结束后,不会马上清理状态,而是会多保留 allowLateness 一样长的时间;如果还有数据在这段时间到来,则继续之前的状态进行计算。(适用于:DataStream、SQL)

    • SideOutput(侧输出流):这种方式需要对迟到数据打一个 tag,然后在DataStream 上根据这个 tag 获取到迟到数据流,然后业务层面自行选择进行处理。(适用于:DataStream)

  • 增量计算

    • 每条数据到来,直接进行计算,window 只存储计算结果。比如计算 sum,状态中只需要存储 sun 的结果,不需要保存每条数据
    • 典型的 reduce、aggregate 等函数都是增量计算 image.png
  • 全量计算

    • 每条数据到来,会存储到 window 的 state 中,等到window 触发计算的时候,将所有数据拿出来一起计算
    • 典型的 process 等函数都是全量计算 image.png
  • EMIT 触发

    • EMIT:在 Window 没有结束的时候,提前把 window 计算的部分输出出来。
    • 实现:
      • DataStream 里面通过自定义 Trigger 来实现,Trigger 的结果可以是:FIRE(触发计算,但是不清理)、CONTINUE、PURGE、FIRE_AND_PURGE...
      • SQL 里面通过配置:table.exec.early-fire.enabled=true,或者 table.exec.early-fire.delay=(time)

3.2 高级优化

  • mini-batch 优化

image.png

  • Ddistinct 计算状态复用

image.png