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

76 阅读5分钟

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

Lect04. 流计算中的 Window 计算

01. 概述

1.1 流式计算 VS 批式计算

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

特性批式计算场景
数据存储HDFS、HiveKafka、Pulsar
数据时效性天级别(凌晨来跑昨天的数据)分钟级别
准确性精准精准和(天然的乱序、乱时到、延迟,舍弃快速加工的能力)
典型计算引擎Hive、Spark、FlinkFlink
计算模型Exactly-OnceAt Least Once / Exactly Once
资源模型定时调度(算完就结束了)长期持有(实时处理和输出)
主要场景离线天级别数据报表实时数仓、实时营销、实时风控

1.2 批处理

批处理模型典型的数仓架构为T+1架构,数据计算是天级别的,当天只能看到前一天的计算结果。

通常使用的计算引擎为Hive或者Spark等。计算的时候,数据是完全ready的,输入和输出都是确定性的。

小时级批计算

问题:

  • 资源消耗大
  • 规定时间可能做不到

如何做到更实时?↓

1.3 处理时间窗口

实时计算——处理时间窗口

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

1.4 处理时间 VS 事件时间

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

1.5 事件时间窗口

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

什么时候窗口才算结束?

1.6 Watermark

时间戳:在数据中插入一些watermark,来表示当前的真实时间

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

可以分辨出迟到的数据,并进行特殊处理

02. Watermark

2.1 什么是Watermark

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

2.2 如何产生Watermark

  • SQL
  • DataStream

2.3 如何传递Watermark

典型问题

Per-partition Vs per-subtask watermark生成

Per-subtask watermark生成

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

Per-partition watermark生成

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

部分partition/subtask断流

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

解决方案:ldle source

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

迟到数据处理

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

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

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

03. Window

3.1 Window应用

定义窗口:

  • SQL API
  • DataStream API

滚动窗口

根据数据决定划分窗口

窗口划分:

  • 每个key单独划分
  • 每条数据只属于一个窗口

窗口触发:

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

滑动窗口

窗口划分:

  • 每个key单独划分
  • 每条数据可能属于多个窗口

窗口触发:

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

会话窗口

窗口划分:

是一个动态过程

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

窗口触发:

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

迟到数据处理

怎么定义迟到

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

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

只有事件时间下才会有迟到的数据

迟到数据默认处理方式

丢弃

其他处理方式

  • Allow lateness

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

  • SideOutput(侧数据流)

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

增量 VS 全量计算

  • 增量计算:

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

  • 全量计算:

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

EMIT触发

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

如何实现

在DataStream里面可以通过自定义Trigger来实现

Trigger的结果可以是:

  • CONTINUE
  • FIRE
  • PURGE
  • FIRE_AND_PURGE

SQL也可以使用,通过配置

3.2 优化

  1. Mini-batch 优化解决频繁访问状态的问题
  2. local-global优化解决倾斜问题
  3. Distinct状态复用降低状态量
  4. Pane优化降低滑动窗口的状态存储量