深入理解 Flink(四)Flink Time+WaterMark+Window 深入分析

深入理解 Flink 系列文章已完结,总共八篇文章,直达链接:
深入理解 Flink (一)Flink 架构设计原理
深入理解 Flink (二)Flink StateBackend 和 Checkpoint 容错深入分析
深入理解 Flink (三)Flink 内核基础设施源码级原理详解
深入理解 Flink (四)Flink Time+WaterMark+Window 深入分析
深入理解 Flink (五)Flink Standalone 集群启动源码剖析
深入理解 Flink (六)Flink Job 提交和 Flink Graph 详解
深入理解 Flink (七)Flink Slot 管理详解
深入理解 Flink (八)Flink Task 部署初始化和启动详解

Flink Window 常见需求背景

需求描述

每隔 5 秒,计算最近 10 秒单词出现的次数 —— 滑动窗口
每隔 5 秒,计算最近 5 秒单词出现的次数 —— 滚动窗口
在这里插入图片描述

关于 Flink time 种类 TimeCharacteristic

在这里插入图片描述

  • ProcessingTime
  • IngestionTime
  • EventTime

WindowAssigner 的子类

  • SlidingProcessingTimeWindows
  • SlidingEventTimeWindows
  • TumblingEventTimeWindows
  • TumblingProcessingTimeWindows

使用 EventTime + WaterMark 处理乱序数据

示意图:
在这里插入图片描述

  • 使用 onPeriodicEmit 方法发送 watermark,默认每 200ms 发一次。
  • 窗口起始时间默认按各个时区的整点时间,支持自定义 offset。

Flink Watermark 机制定义

有序的流的 Watermarks

在这里插入图片描述

无序的流的 Watermarks

在这里插入图片描述

多并行度流的 Watermarks

在这里插入图片描述

深入理解 Flink Watermark

Flink Window 触发的条件:

  1. watermark 时间 >= window_end_time
  2. 在 [window_start_time, window_end_time) 区间中有数据存在(注意是左闭右开的区间),而且是以 event time 来计算的

Flink 处理太过延迟数据

Flink 丢弃延迟太多的数据

企业生产中一般不用。

Flink 指定允许再次迟到的时间

治标不治本,企业生产中一般不用。

Flink 收集迟到的数据单独处理

企业生产中应用较为广泛。

Flink 多并行度 Watermark

一个 window 可能会接受到多个 waterMark,我们以最小的为准。
在这里插入图片描述

Flink Window 概述

官网介绍

https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/dev/datastream/operators/windows/
在这里插入图片描述

Flink Window 分类

Flink 的 window 分为两种类型的 Window,分别是:Keyed Windows 和 Non-Keyed Windows,他们的使用方式不同:

// Keyed Windows 
stream
    .keyBy(...) <- keyed versus non-keyed windows
    .window(...) <- required: "assigner"
    [.trigger(...)] <- optional: "trigger" (else default trigger)
    [.evictor(...)] <- optional: "evictor" (else no evictor)
    [.allowedLateness(...)] <- optional: "lateness" (else zero)
    [.sideOutputLateData(...)] <- optional: "output tag" (else no side output for late data)
    .reduce/aggregate/apply() <- required: "function"
    [.getSideOutput(...)] <- optional: "output tag"
// Non-Keyed Windows
stream
    .windowAll(...) <- required: "assigner"
    [.trigger(...)] <- optional: "trigger" (else default trigger)
    [.evictor(...)] <- optional: "evictor" (else no evictor)
    [.allowedLateness(...)] <- optional: "lateness" (else zero)
    [.sideOutputLateData(...)] <- optional: "output tag" (else no side output for late data)
    .reduce/aggregate/apply() <- required: "function"
    [.getSideOutput(...)] <- optional: "output tag"

Window 的生命周期

  1. 当属于某个窗口的第一个元素到达的时候,就会创建一个窗口。
  2. 当时间(event or processing time)超过 window 的结束时间戳加上用户指定的允许延迟(Allowed Lateness)时,窗口将被完全删除。
  3. 每个 Window 之上,都绑定有一个 Trigger 或者一个 Function(ProcessWindowFunction, ReduceFunction, or AggregateFunction)用来执行窗口内数据的计算。
  4. 可以给 Window 指定一个 Evictor,它能够在 after the trigger fires 以及 before and/or after the function is applied 从窗口中删除元素。

Flink Window 类型

Flink 流批同一前后的 Window 分类:
在这里插入图片描述

tumblingwindows —— 滚动窗口

在这里插入图片描述

slidingwindows —— 滑动窗口

在这里插入图片描述

session windows —— 会话窗口

在这里插入图片描述

global windows —— 全局窗口

在这里插入图片描述

Flink Window 操作使用

高级玩法:自定义 Trigger、自定义 Evictor,读者可自行搜索相关文章与代码。

Flink Window 增量聚合

  • reduce(ReduceFunction)
  • aggregate(AggregateFunction)
  • sum()
  • min()
  • max()
  • sum()

Flink Window 全量聚合

  • apply(WindowFunction)
  • process(ProcessWindowFunction)

Flink Window Join

// 在 Flink 中对两个 DataStream 做 Join
// 1、指定两张表
// 2、指定这两张表的链接字段
stream.join(otherStream) // 两个流进行关联
    .where(<KeySelector>) // 选择第一个流的key作为关联字段
    .equalTo(<KeySelector>) // 选择第二个流的key作为关联字段
    .window(<WindowAssigner>) // 设置窗口的类型
    .apply(<JoinFunction>) // 对结果做操作 process apply = foreach

Tumbling Window Join

在这里插入图片描述

Sliding Window Join

在这里插入图片描述

Session Window Join

在这里插入图片描述

Interval Join

在这里插入图片描述
核心代码示例:

DataStream<Integer> orangeStream = ...;
DataStream<Integer> greenStream = ...;
orangeStream
    .keyBy(<KeySelector>)
    .intervalJoin(greenStream.keyBy(<KeySelector>))
    .between(Time.milliseconds(-2), Time.milliseconds(1))
    .process (new ProcessJoinFunction<Integer, Integer, String(){
        @Override
        public void processElement(Integer left, Integer right, Context ctx, Collector<String> out) {
            out.collect(first + "," + second);
       }
    });
  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要触发Flink的event time temporal join,需要满足以下条件: 1. 数据源必须有时间戳(timestamp)字段,用于标识事件发生的时间。 2. 数据源必须定义Event TimeWatermark,用于处理乱序事件数据。 3. 执行join操作时,需要使用Window函数将事件流分割为固定时间段的窗口,以便进行join操作。 4. 在join操作中,需要将窗口中的数据按照时间戳进行排序。 5. 确保所有数据源都使用相同的时间语义(Event Time)。 以下是一个示例代码,演示如何触发Flink的event time temporal join: ``` DataStream<Order> orders = env .addSource(new OrderSource()) .assignTimestampsAndWatermarks(new OrderTimestampExtractor()); DataStream<Payment> payments = env .addSource(new PaymentSource()) .assignTimestampsAndWatermarks(new PaymentTimestampExtractor()); orders.join(payments) .where(order -> order.getCustomerId()) .equalTo(payment -> payment.getCustomerId()) .window(TumblingEventTimeWindows.of(Time.seconds(10))) .apply(new JoinFunction<Order, Payment, String>() { @Override public String join(Order order, Payment payment) throws Exception { return "Order: " + order.toString() + ", Payment: " + payment.toString(); } }) .print(); ``` 在上述代码中,orders和payments分别是两个数据源,分别代表订单和支付信息。我们使用OrderTimestampExtractor和PaymentTimestampExtractor对它们进行时间戳和Watermark的处理。 在join操作中,我们使用where和equalTo指定订单和支付信息的关联字段,使用TumblingEventTimeWindows将事件流分割为10秒的窗口,然后使用JoinFunction进行join操作,并将结果打印出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值