这是我参与「第四届青训营」笔记创作活动的第 6 天
1、 流计算概述
1.1 处理时间窗口
- 实时计算:处理时间窗口
- 数据实时流动、计算,窗口结束直接发送结果,不需要同期调度任务
1.2 处理时间 VS 事件时间
- 处理时间:数据在流式计算系统中真正处理时所在机器的当前时间
- 事件时间:数据产生的时间,比如客户端、传感器、后端代码等上报数据时的时间
1.3 事件时间窗口
- 实时计算:事件时间窗口
- 数据实时进入到真实事件发生的窗口中进行计算,可以有效的处理数据延迟和乱序
- 窗口结束时间:没办法预知。故引出:Watermark
1.4 Watermark
- 在数据中插入一些watermark,来表示当前的真实时间
- 在数据乱序的时候,watermrk 比较重要,它可以用来在乱序容忍和实时性之间做一个平衡
2、 关于Watermark
2.1 Watermark了解
- Watermark 表示当前真实的事件时间
- 如何产生:
- 如何传递:
- 如何通过 Flink UI 观察 Watermark:
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 结束时间到达的时候一次性触发
- Sliding Window(滑动窗口)
- 窗口划分:每个 key 单独划分;每条数据可能会属于多个窗口
- 窗口触发:Window 结束时间到达的时候一次性触发
- Session Window(会话窗口)
- 窗口划分:每个 key 单独划分;每条数据会单独地划分一个窗口如果 Window 之间有交集,则会对窗口进行 merge
- 窗口触发:Window 结束时间到达的时候一次性触发
3.1.2 数据迟到
-
定义:
-
产生情况:只有事件时间下才会有迟到的数据
-
默认处理:丢弃
-
迟到数据处理:
-
Allow lateness:这种方式需要设置一个允许迟到的时间。设置之后,窗口正常计算结束后,不会马上清理状态,而是会多保留 allowLateness 一样长的时间;如果还有数据在这段时间到来,则继续之前的状态进行计算。(适用于:DataStream、SQL)
-
SideOutput(侧输出流):这种方式需要对迟到数据打一个 tag,然后在DataStream 上根据这个 tag 获取到迟到数据流,然后业务层面自行选择进行处理。(适用于:DataStream)
-
-
增量计算
- 每条数据到来,直接进行计算,window 只存储计算结果。比如计算 sum,状态中只需要存储 sun 的结果,不需要保存每条数据
- 典型的 reduce、aggregate 等函数都是增量计算
-
全量计算
- 每条数据到来,会存储到 window 的 state 中,等到window 触发计算的时候,将所有数据拿出来一起计算
- 典型的 process 等函数都是全量计算
-
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 优化
- Ddistinct 计算状态复用