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

241 阅读6分钟

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

今天笔记主要分为四个部分:

image.png

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

  1. 事件时间:数据产生的时间。
  1. 处理时间:数据在流式计算系统中真正处理时所在机器的当前时间。

实时计算的核心功能

Watermark机制

watermark就是系统认为当前真实的事件时间。

Watermark机制就是在数据流中插入一些真实时间,如果之后有比这个时间小的时间,那我们就可以认定这个时间戳对应的数据是延迟数据,不影响之前窗口的结束。

watermark的传递

watermark一对一传递时下游直接采用上游的watermark;watermark一对多传递时,下游选择多个上游传来的watermark里面最小的watermark作为自己的watermark

watermark的典型问题

  1. 生成策略的问题:

Per-subtask watermark生成造成的问题时如果一个source subtask消费多个partution,那么多个partition之间的数据读取可能会加剧乱序程度。

Per-subtask watermark生成策略基于每个partition单独的watermark生成机制,有效避免了上面的问题。

  1. 部分partition/subtask断流:

如果上游一个suntask的watermark不更新了,那么下游的watermark也不更新了。

解决方案:Idle source

当某个subtask断流超过配置的idle超时时间时,将当前subtask置为idle,并下发一个idle的状态给下游,下游在计算自身的watermark时,可以忽略当前是idle的那些subtask。使正常数据可以流通。"

  1. 迟到数据的处理
  • window聚合,默认会丢弃迟到数据
  • 双流join,如果是outer join,则可以认为它不能join到任何数据
  • CEP,默认丢弃

Window机制

分类

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

3大基本窗口类型的定义、使用以及核心原理

1. Tumble Window(滚动窗口)

  • 窗口划分:
  1. 每个key单独划分
  1. 每条数据只会属于一个窗口
  • 窗口触发:

Window结束时间到达的时候一次性触发。

2. Sliding Window(滑动窗口)

  • 窗口划分:
  1. 每个key单独划分
  1. 每条数据可能会属于多个窗口
  • 窗口触发:

Window结束时间到达的时候一次性触发。

3. Session Window(会话窗口)

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

Window结束时间到达的时候一次性触发。

窗口机制中的最核心的优化以及原理

迟到数据处理

  1. 定义:一条数据到来后,会用WindowAssigner给他划分一个window,如果划分出来的窗口末尾比当前watermark值还小,则被认为是迟到数据。
  1. 只有事件时间下才会有迟到的数据
  1. 迟到数据的默认处理是丢弃
  1. 处理机制:
  • Allow lateness

这种方式就是设置一个允许迟到的时间,设置之后,窗口正常计算。结束后,不会马上清理状态,而是多保留

Allow lateness这么长时间,如果期间有数据姗姗来迟,会继续之前的状态进行计算。适用于DataStream、SQL.

个人理解就是给数据一定时间的迟到缓冲区,就像上班迟到了,只要你没迟到太久,没有过了老板允许的时间就行。

  • SideOutput(侧输出流)

这种方式是对迟到数据添加一个标签,然后在数据流上根据这个标签去获取迟到数据流,在业务层面自行选择进行处理。适用于DataStream。

个人的理解就是给迟到员工在考勤上打个记号,看后期老板咋处理。

增量VS全量计算

增量计算

每条数据到来,直接进行计算,window只存储计算结果,不需要保存每条数据。典型函数有reduce、aggregate。SQL的聚合只有增量计算。

全量计算

每条数据到来,会存储到window的state中,等到window触发计算时,将所有数据拿出来一起计算。典型函数有process.

EMIT触发

背景:当窗口比较大,那么计算结果输出延迟就比较高,失去了实时计算的意义。

定义:在window没有结束的时候,提前把window计算的部分结果输出出来。

实现:在DataStream中通过自定义Trigger来实现,Trigger结果有:

  • CONTINUE
  • FIRE(触发计算,但是不清理)
  • PUREG
  • FIRE_AND_PURGE

高级优化

mini-batch优化

缺点;输出量大,算子需要保留状态(内存,外部)。

那么就需要解决中间结果偏多, 状态访问较频繁这种缺点,所以引入了人mini-batch优化。

mini-batch就是让算子攒一小批数据,然后小批数据读一次状态,输出,写回数据。

倾斜优化 local-global

倾斜优化计算之前不需要对数据进行shuffle,但需要对数据进行预处理,把中间结果发到最终去处理。使热点问题得以缓解。

Distinct计算状态复用

当用户的sql语句写成如上代码所示时,那么就可以优化成下面图表所示。

Pane优化

当有窗口交叠的时候,如果我们计算所有交叠牵扯的窗口的话,如果窗口大小很大,但滑动时间太短,则产生的数据过于繁杂。那么我们可以并不在窗口到来的时候直接计算出最后的结果,而是把窗口划分成更小的粒度(pane),那么一条数据只属于一个pane,计算量和存储量就大大减少,但是在最终输出的时候需要合并pane。

案例分析

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

解决方案:滑动窗口+EMIT

方案一:

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

方案二:

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

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

解决方案:会话窗口

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