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

227 阅读12分钟

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

一、概述

1.流式计算vs批式计算

特性批式计算流式计算
数据存储HDFS、HiveKafka、Pulsar
数据时效性天级别分钟级别
准确性精准精准和时效性之间取得
典型计算引擎Hive、Spark、FlinkFlink
计算模型Exactly-onceAt Least Once/Exactly Once
资源模型定时调度长期持有
主要场景离线天级别数据报表实时数仓、实时营销、实时风控

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

2.批处理

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

image.png

划分为以小时单位调度,是否可以做到更实时的数仓?

1.批计算需要申请释放资源,有一个周期调度的过程,比较消耗资源

2.线上的数仓任务从几分钟到几小时不等,数仓的建模是分层的,整个的流程要在1个小时之内完成比较困难 image.png

如何更实时?

3.处理时间窗口

实时计算:处理时间窗口

数据是实时流动,实时计算,窗口结束直接发送结果,不需要周期调度任务

image.png

流式任务可以直接对数据划分成一个小时,一个小时的任务,窗口结束后,直接下发,不需要等小时结束后数据准备完了再计算,而是每来一条就计算。

4. 处理时间VS时间时间

image.png

通常处理时间有一些延迟。

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

5.事件时间窗口

实时计算:事件时间窗口

image.png

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

什么时候窗口才算结束?

有可能11点前的数据在11点半之后还会到

6.Watermark

在数据中插入一些watermark,来表示当前的真实时间,配合事件窗口处理数据乱序。

image.png

这个数据时间戳依次递增,属于比较完美的时间。11之后,有一个watermark(11),认为已经到了11时刻了,如果后面有比11小的数据到来,就认为时延迟数据,不应该参与前面的计算。

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

image.png

watermark(11)左边没有比他小的数据,如果有,说明是一个迟到的数据,前面的窗口已经计算过了,对他进行特殊处理,不影响之前的窗口计算。

二、watermark

1.什么是Watermark

表示系统认为的当前真实的事件时间

在flink里如何产生watermark?

Flink中有三大API,第一类是SQL,TABLE API,第二类是DtaStream

第一类SQL

image.png

倒数第二行生成watermark,从原始数据order_time减去5s作为watermark的数值。

第二类DataStream

image.png

用事件时间减去固定的20s作为watermark的数值

3.如何传递Watermark?

image.png

三个task,source,map,window。一个source可以消费两个MQ的分区partition,source的watermark是33,传递给下游,下游收到之前watermark是29,一对一传递是比较简单的。多对多传递,例如weindow1会取收到的最小值,作为watermark。

4.如何通过Flink UI观察watermark?

image.png

为什么开发了window有数据输入没有数据输出?看watermark是否是正常的。

source读出来会有一个sql生成的assigner的算子,传给下游window生成的算子,会有一个时间戳是否是正常的,如果没有时间戳,可能上游数据不够多,或者数据有异常。

5.典型问题一

Per-partition VS per-subtask watermark生成

Per-subtask watermark生成

早期版本都是这种机制。典型的问题是如果一个source suubtask消费多个partition,分区之间读取可能速度不同,那么多个partition之间的数据读取可能会加剧乱序程度。

Per-partition watermark生成

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

6.典型问题二

部分partition/subtask断流

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

解决方案:Idle source

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

7.典型问题三

迟到数据处理

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

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

  • window聚合,默认会丢弃迟到数据

  • 双流join,如果是outerjoin,则可以认为它不能join到任何数据

  • CEP,默认丢弃

三、Window

1.基本功能

(1)window分类与使用

典型的window:

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

其它Window:

  1. 全局window
  2. count window
  3. 累计窗口
  4. ...

Flink 的API是分层的

image.png

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

sql在聚合的地方加一个TUMBLE ,窗口大小时间

datastream做一个keyby,加一个窗口,5秒的处理时间,做一个sum

  1. 滚动窗口

image.png

三个用户,一共有14个窗口

窗口划分:

  1. 每个key单独划分

  2. 每条数据只会属于一个窗口

窗口触发:

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

数据进来就开始计算,输出是等窗口结束输出

  1. 滑动窗口

image.png

窗口划分:

  1. 每个key单独划分

  2. 每条数据可能会属于多个窗口

窗口触发:

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

  1. 会话窗口

image.png

数据到来,不能确定数据最终所属的窗口是哪个,动态划分,新数据到来可能和前窗口合并。

窗口划分:

  1. 每个key单独划分

  2. 每条数据会单独划分为一个窗口,如果window之间有交集,则会对窗口进行merge>

窗口触发:

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

(2)迟到数据处理

怎么定义迟到?

一条数据到来后,会用WindowAssigner给它划分一个window,一般时间窗口是一个时间区间,比如[10:00,11:00),如果划分出来的window end比当前的watermark值还小,说明这个窗口已经出发了计算了,这条数据会被认为是迟到数据。

什么情况下会产生迟到数据?

只有事件时间下才会有迟到的数据,处理时间不会产生。

迟到数据默认处理?丢弃

image.png

  1. Allow lateness

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

适用于:DataStream、SQL

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

适用于:DataStream

image.png

增量计算:

  • 每条数据到来,直接进行计算,window只存储计算结果。比如计算sum,状态中只需要存储sum的结果,不需要保存每条数据。
  • 典型的reduce、aggregate等级函数都是增量计算 -SQL的聚合只有增量计算

image.png

全量计算:

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

(3)EMIT触发

什么叫EMIT? 通常来讲,winsow都是在结束的时候才能输出结果,比如1h的tumble window,只有在1个小时结束的时候才能统一输出结果。

如果窗口比较大,把比如1h或者1天,甚至于更大的话,那计算结果输出的延迟就比较高,失去了实时计算的意义。

EMIT输出指的是,在window没有结束的时候,提前把window计算的部分结果输出出来,可以中间结果输出多次,下游可以看到不断变换的结果,也需要用到retract机制,最终满足一致性语义。

怎么实现? 在DataStream里可以通过自定义Trigger来实现,Trigger的结果可以是:

  • CONTIUNE
  • FIRE(出发计算,但是不清理)
  • PURGE
  • FIRE_AND_PURGE

SQL也可以使用,通过配置:

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

2.Window-高级优化

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

image.png

中间输出每条结果,输出量大。user,count值状态需要保存,放到内存里或放到外部CB,大的状态一般会放到外部,内存会比较可控。放到外部会有序列化和反序列化,每条数据来了之后都要读取之前的状态,计算,写入,输出,对CPU开销比较大。

image.png

Mini-batch解决上述两个问题。积攒一小批数据,读一次状态,处理这一批数据,输出,写回状态。

但另外一个问题,这个机制的拓扑可能比较复杂,延迟可能比较高,真实的场景需要用到checkpoint传递机制和watermark协作,在上游添加一个assigner的算子,统一发起指令,开始一个新的mini-batch信号,下游收到信号后,就把之前的数据计算输出写状态,再去传递这个信号,在一个上游的信号周期内,完成整个链路的mini-batch的周期计算。

2.倾斜优化-local-global

image.png 数据倾斜定义:

是指在大规模并行处理的数据中,其中某个运行节点处理的数据远远超过其他部分,这会导致该节点压力极大,最终出现运行失败从而导致整个任务的失败。

产生数据倾斜的原因主要有 2 个方面:

业务上有严重的数据热点

技术上大量使用了 KeyBy、GroupBy 等操作,错误的使用了分组 Key,人为产生数据热点。

3.Dinstinct计算状态复用降低状态量

image.png

image.png 它是一个map,key是到达的数据,value是固定值表示来或没来过,状态复用量是比较客观的,离线的话服用程度是非常高的。

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

image.png

既属于window1,也属于window2,一天的窗口1小时滑动,每条数据参与的计算量是比较大的,窗口的开销也是比较大的。

image.png

不在数据到来把最终结果计算出来,三小时的窗口1小时的滑动,划分成更小的力度key,最终组合成窗口,每条数据来了后就像普通的滚动窗口,每条数据只属于一个window,计算量和存储量比较可控,最终需要再窗口输出结果的时候做一个merge。

四、案例

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

image.png

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

做一个滚动窗口1天,计算count uid,得到一天内的用户的dau结果,用EMIT机制,能够实时输出,得到日货曲线输出。

问题: group by只有时间窗口,最终计算需要有高并发的全局窗口计算才能够聚合到所有用户的uid。所有数据都需要在一个subtask中完成窗口计算,无法并行。

image.png

通过子查询根据用户分桶,比如分成一万个桶,计算每个桶里的uid,通过二次聚合,但并发计算,把一万个桶全局聚合,取sum值得到最终结果。

  • table.exec.emit.early-fire.enabled=true
  • table.exec.emit.early-fire.delay=(time)
  • table.exec.emit.allow-retract-input=true 通过两阶段聚合来把数据来把数据打散,完成第一轮聚合,第二轮聚合只需要对各个分桶的结果求和即可。(倾斜优化)

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

问题描述:大数据任务(特指离线任务),需要定期调度,运行时通常会有多个container启动并运行,每个container在运行结束的时候,YARN会负责将他的资源使用(CPU、内存)情况上报。一般大数据任务运行时间从几分钟到几小时不等。

需求: 根据YARN上报的各个container的信息,在任务结束的时候,尽快的计算出一个任务运行所消耗的总的资源。 假设前后两个container结束时间差不超过10min

image.png

应用id做一个groupby,写一个会话窗口gap设置成10分钟,对会话窗口内的所有container进行求和,就可以得到场景的最终结果。

五、参考文章

剖析Flink出现数据倾斜和解决办法_Platina_Tomato的博客-CSDN博客_flink数据倾斜

Flink优化04---数据倾斜_Johnson8702的博客-CSDN博客_flink如何解决数据倾斜

Flink技术源码解析(一):Flink概述与源码研读准备_吃鱼的羊的博客-CSDN博客

Sql优化(二) 快速计算Distinct Count_郭俊JasonGuo的博客-CSDN博客