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

148 阅读7分钟

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

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

课程回顾:

  1. 流式计算中动态表的概念;
  2. Flink 中的 State 和 Checkpoint 的基本原理;
  3. Flink 中的 Retract 机制,以及算子如何产生和处理 Retract 数据;
  4. 在 Flink 中如何实现 Exactly-Once 的语义。

一、本堂课重点内容

  • 了解实时计算和批式计算的本质区别,以及实时计算所带来的的新的机遇和挑战

  • 了解实时计算中的核心功能:Watermark 机制、Window 机制

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

  • 了解窗口机制中的最核心的优化及其原理

二、详细知识点介绍

1. 概述

简述流式计算的基本概念,与批式计算相比的难点和挑战

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 事件时间窗口

实时计算:事件时间窗口

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

什么时候窗口才算结束?

在数据中插入一些 watermark,来表示当前的真实时间,它可以用来在乱序容忍和实时性之间做一个平衡。

43.JPG

01.小结

  1. 批式计算一般是 T+1 的数仓结构

  2. 数据实时性越高,数据的价值越高

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

  4. 事件时间需要 Watermark 配合来处理乱序

2. Watermark

Watermark 的含义、生成方法、传递机制,以及一些典型场景的问题和优化

2.1 什么是 Watermark?

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

2.2 如何产生 Watermark?

SQL

CREATE TABLE Orders(
    user BIGINT,
    product STRING,
    order_time TIMESTAMP(3),
    WATERMARK FOR order_time AS order_time - INTERVAL '5' SECOND
) WITH ( . . . );

DataStream

WatermarkStrategy
    .<Tuple2<Long, String>>forBoundOutOfOrderness(Duration.ofSeconds(20))
    .withTimestampAssigner((event, timestamp) -> event.f0);

2.3 如何传递 Watermark?

44.JPG

图源:教学PPT

2.5 典型问题

Per-partition VS per-subtask watermark 生成

部分 partition/subtask 断流

解决方案:Idle source

迟到数据处理

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

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

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

  • CEP,默认丢弃

3. Window

Window 基本功能和高级优化

3.1 Window 分类

典型的 Window:

  1. Tumble Window(滚动窗口)

  2. Sliding Window(滑动窗口)

  3. Session Window(会话窗口)

其它 Window:

  1. 全局 Window

  2. Count Window

  3. 累计窗口

  4. ......

—— 滚动窗口

窗口划分:

  1. 每个 key 单独划分

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

窗口触发:

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

—— 会话窗口

  1. 每个 key 单独划分

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

窗口触发:

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

—— 迟到数据处理

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

只有事件时间下才会有迟到的数据,默认丢弃处理。

  1. Allow lateness

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

适用于:DataStream、SQL

  1. SideOutput(侧输出流)

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

适用于:Datastream

final OutputTag<T> lateOutputTag = new OutputTag<T>("late-data"){};

DataStream<T> input = ...;

SingleOutputStreamOperator<T> result = input
    .keyBy(<key selector>)
    .window(<window assigner>)
    .allowedLateness(<time>)
    .sideOutputLateData(lateOutputTag)
    .<window transformation>(<window function>);
    
DataStream<T> lateStream = result.getSideOutput(lateOutputTag);

—— 增量 VS 全量计算

增量计算:

  • 每条数据到来,直接进行计算,window 只存计算结果。比如计算 sum,状态中只需要存储 sum 的结果,不需要保存每条数据.

  • 典型的 reduce、aggregate 等函数都是增量计算

  • SQL中的聚合只有增量计算

全量计算:

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

  • 典型的 process 函数就是全量计算

—— EMIT 触发

什么叫 EMIT?

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

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

EMIT 输出指的是,在 window 没有结束的时候,提前把 window 计算的部分结果输出出来。

怎么实现?

在 DataStream 里面可以通过自定义 Trigger 来实现 Trigger 的结果可以是:

  • CONTINUE

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

  • PURGE

  • FIRE AND PURGE

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

  • table.exec.emit.early-fire.enabled=true

  • table.exec.emit.early-fire.delay={time}

—— 小结

  1. 三种(滚动、滑动、会话)窗口的定义

  2. 迟到的数据处理:AllowLateness、SideOutput

  3. 增量计算和全量计算

  4. EMIT 触发提前输出窗口的结果

3.2 Window - 高级优化

—— Mini-batch 优化

45.JPG

—— 倾斜优化 - local-global

46.JPG

图源:教学PPT

03.小结

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

  2. local-global 优化解决倾斜问题

  3. Distinct 状态复用降低状态量

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

4. 案例分析

抖音 DAU 实时曲线计算、大数据任务资源使用实时统计分析

三、课程总结

  1. 第一部分介绍了流式计算基本概念,以及和批式计算的区别

  2. 第二部分介绍了 watermark 的含义、如何生成、如何传递,以及如何处理部分 partition 断流的问题

  3. 第三部分介绍了三种基本的 window 的定义,以及迟到数据处理、增量计算 VS 全量计算、EMIT 输出;同时也介绍了 local-global 优化、mini-batch 优化、distinct 状态优化、滑动窗口的 pane 的优化等

  4. 两个案例介绍滚动窗口、会话窗口,以及两阶段聚合解决倾斜问题