【Flink】WaterMark 实战

WaterMark 实战

  • [1.WaterMark 触发详解](#1.WaterMark 触发详解)
  • 2.实际案例

1.WaterMark 触发详解

例如,现在我们有了一个 [12:00:00-12:00:10) 的时间窗口,现在事件如下图所示顺序 A、B、C、D、E、F ... 到达。

在未设置 WaterMark 的情况下,当元素 C 到达的时候,便会触发窗口 [12:00:00-12:00:10) 进行计算,因为 C 元素的时间已经满足大于等于窗口 [12:00:00-12:00:10) 的结束时间 12:00:10 了。

此时呢,该窗口中仅会有 A、B 两个元素,如果从事件时间划分来讲,D、F 应也属于窗口 [12:00:00-12:00:10) 内的元素,但是由于 C 提前到来(D、F 延迟了)触发了计算,因 Flink 时间窗口的生命周期限制,[12:00:00-12:00:10) 这个窗口,再也不会打开。

其最后将导致 D、F 再无可归属窗口,D、F 因此成了无用数据,最终会被抛弃掉!

当我们引入了 WaterMark 水印机制,设置了延迟时间后,事件时间窗口的触发时机由事件时间决定变为了由 WaterMark 决定

比如我们现在设置了窗口允许数据最大延迟时间为 5s。

  • A 数据到达:WaterMark = max{12:00:01} - 5 = 11:59:56 < 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,不会触发计算。
  • B 数据到达:WaterMark = max{12:00:05,12:00:01} - 5 = 12:00:0 < 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,不会触发计算。
  • C 数据到达:WaterMark = max{12:00:11,12:00:05,12:00:01} - 5 = 12:00:06 < 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,不会触发计算。
  • D 数据到达:WaterMark = max{12:00:08,12:00:11,12:00:05,12:00:01} - 5 = 12:00:06 < 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,不会触发计算。
  • ...... 直到 某一个事件时间 - 5 >= 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,才会触发窗口 [12:00:00-12:00:10) 计算!
  • G 数据据到达:WaterMark = max{12:00:15,12:00:09,12:00:08,12:00:11,12:00:05,12:00:01} - 5 = 12:00:10 = 窗口 [12:00:00-12:00:10) 的结束时间 12:00:10,此时窗口 [12:00:00-12:00:10) 的归属元素有 A、B、D、F,窗口存在元素,会触发计算!!!!
  • 1️⃣ WaterMark 只是决定了窗口的触发时机,并非可以改变元素归属的窗口(事件应归属的窗口是由事件本身的事件时间决定的),例如上方元素 C、G,虽然根据设置的延迟时间可能触发窗口 [12:00:00-12:00:10) 计算,但其本身时间不归属于窗口之内,因为窗口 [12:00:00-12:00:10) 中永远不会有 >= 12:00:10 的元素存在。
  • 2️⃣ WaterMark 可以在一定程度上解决事件乱序问题,但严重的乱序问题依然无法解决!

例如,在事件 G 后又来了事件 H(乱序比较严重!!因为前边元素都 12:00:15 了,自己反而才 12:00:07)。如果设置的允许最大延迟时间为 5s,元素 G 依然满足触发窗口 [12:00:00-12:00:10) 计算销毁,后来的元素 H 便再无可归属的时间窗口了,所以 H 仍然会丢失!!

基于这种情况,如果想避免 H 数据丢失怎么办呢?我们可以让 G 无法触发窗口 [12:00:00-12:00:10) 就行,即允许延迟时间再设置大一点,比如允许延迟 10s ... 延迟 10s 后,至少有了事件时间为 12:00:20 的事件到来才会触发计算了,这样 H 就不会丢了。但如此设置,又避免不了更延迟的数据,比如延迟了 20s 的数据,所以说,WaterMark 只能在一定程度上解决乱序问题!!

当然以上情况,我们可以结合侧位输出来收集更为延迟的数据,避免延迟数据丢失(这个后边会讲),但是!事件时间延迟,主要问题在生产端!如果真要解决这个问题,应该从生产事件的生产端入手,而非极力依托于计算框架!!

2.实际案例

我们定义一个 10s 的滚动窗口,且允许数据最大延迟为 5s。

sql 复制代码
CREATE TABLE user_income (
    income INT,
    times TIMESTAMP(3),
    WATERMARK FOR times AS times - INTERVAL '5' SECOND
) WITH (
    'connector' = 'filesystem',
    'path' = 'input/sales04.csv',
    'format' =  'csv'
);

CREATE TABLE output (
    win_start TIMESTAMP(3),
    win_end TIMESTAMP(3),
    hour_income BIGINT
) WITH (
    'connector' = 'print'
);

INSERT INTO output
SELECT
    TUMBLE_START(times,INTERVAL '10' SECOND),
    TUMBLE_END(times,INTERVAL '10' SECOND),
    SUM(income)
FROM user_income
GROUP BY TUMBLE(times,INTERVAL '10' SECOND);

构造测试数据

sql 复制代码
10,2021-05-27 22:12:53
10,2021-05-27 22:12:58
10,2021-05-27 22:13:04 -- 不会触发窗口 [2021-05-27 22:12:50, 2021-05-27 22:13:00) 的计算
10,2021-05-27 22:13:03 -- 不会触发窗口 [2021-05-27 22:12:50, 2021-05-27 22:13:00) 的计算
10,2021-05-27 22:12:58
10,2021-05-27 22:13:03 -- 不会触发窗口 [2021-05-27 22:12:50, 2021-05-27 22:13:00) 的计算
10,2021-05-27 22:12:52
10,2021-05-27 22:12:52
10,2021-05-27 22:12:58
10,2021-05-27 22:13:05 -- 将会触发窗口 [2021-05-27 22:12:50, 2021-05-27 22:13:00) 的计算
10,2021-05-27 22:12:59 -- 该条数据所属窗口已经触发了计算,该条数据将会被抛弃
10,2021-05-27 22:13:19 -- 将会触发窗口 [2021-05-27 22:13:00, 2021-05-27 22:13:10) 的计算

运行结果如下:

相关推荐
昵称画5 小时前
交接班记录电子化:三班之间的信息不漏
开发语言·数据库·人工智能·低代码·php
缓慢更新6 小时前
审批的加签与会签:多人意见怎么合
android·java·数据库·低代码·rxjava
跨境联盟7 小时前
大健康实体如何搭建产品差异化:对比普通营养品与合规跨境膳食补充剂服务模式
数据库·ai·健康医疗·健康管理·精准营养
有想法的py工程师7 小时前
PostgreSQL EXPLAIN中的Cost模型分析(random_page_cost参数):优化器眼中的代价世界与执行计划生成
数据库·postgresql
renhongxia17 小时前
边缘AI部署与大模型轻量化技术全景:量化、蒸馏、RAG 与智能体落地实战
大数据·人工智能
前进的李工7 小时前
飞书企业知识库设计+后端高频八股
数据库·redis·后端·mysql·性能优化·飞书·rag
企查查数据服务7 小时前
股权穿透+责任传导是医药并购合规健康度评分卡
大数据·人工智能
泡海椒8 小时前
JQuick-SQL CSV 文件数据接入:转换为内存表后再查询
数据库·sql
YH_Analytics8 小时前
2026 年增亮膜(DBEF)行业市场格局深度解析
大数据·网络
方芯半导体9 小时前
2026工业机器人控制芯片赛道:竞争格局与关键选型指标深度解析
大数据·人工智能·机器人