Flink Watermark示例
Watermark简介
在 Apache Flink 中,水印(Watermark) 是一种用于处理事件时间(Event Time)流数据的机制。它代表了流处理系统中对事件时间进度的理解,用来标识数据流中的时间点,从而帮助确定何时窗口应该关闭并触发计算。
水印的作用
控制窗口计算:Flink 使用水印来决定何时关闭基于事件时间的窗口。例如,在一个 10 分钟的滚动窗口中,只有当水印超过窗口结束时间时,Flink 才会认为该窗口内的所有数据都已经到达,并且可以安全地进行计算。
处理迟到数据:通过设置允许的最大延迟(Allowed Lateness),Flink 可以接收那些晚于预期到达的数据。水印使得我们可以定义如何处理这些迟到的数据,比如将它们添加到已经计算过的窗口中或忽略它们。
水印的工作原理
水印是按照事件时间戳生成的特殊标记,通常表示“在这个时间之前的所有事件都已经到达”。具体来说:
事件时间戳:每个事件都有一个时间戳,这个时间戳反映了事件实际发生的时间,而不是它被处理的时间。
水印生成器(Watermark Generator):这是负责生成水印的组件。它根据输入数据流中的事件时间戳来创建水印。最常见的是使用 forBoundedOutOfOrderness 方法来指定最大乱序程度,即允许的最大延迟时间。
推进水印:随着更多事件的到来,水印逐渐推进。理想情况下,水印应该是递增的,但实际应用中可能会有乱序的情况,因此我们需要设定一个合理的最大乱序时间。
WatermarkStrategy<OrderItem> watermarkStrategy = WatermarkStrategy
.<OrderItem>forBoundedOutOfOrderness(Duration.ofSeconds(5)) // 允许最多5秒的乱序
.withTimestampAssigner((event, timestamp) -> event.updateTime); // 提取事件时间戳的方法
水印的一个重要特性是它可以和允许的最大延迟一起工作,以便处理迟到的数据。例如,如果你设置了一个 1 小时的滚动窗口,并且允许最多 5 分钟的迟到数据,那么即使水印超过了窗口的结束时间,只要数据的事件时间不超过窗口结束时间加上 5 分钟,这些迟到的数据仍然会被包含在窗口计算中。
一、构造数据源
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class OrderItemSource implements SourceFunction<OrderItemSource.OrderItem> {
private volatile boolean isRunning = true;
@Override
public void run(SourceContext<OrderItem> sourceContext) throws Exception {
// 每一秒生生一条数据
for (int i=0; i < 100; i++) {
OrderItem orderItem = new OrderItem(i, i % 2, 1, "商品A", new Random().nextInt(100), 1, System.currentTimeMillis());
System.out.println(orderItem);
sourceContext.collect(orderItem);
TimeUnit.MILLISECONDS.sleep(1000);
}
}
@Override
public void cancel() {
isRunning = false;
}
public static class OrderItem {
public int id;
public int orderId;
public String shopName;
public double paidPrice;
public long updateTime;
public OrderItem() {}
public OrderItem(int id, int orderId, int shopId, String shopName, double paidPrice, int shopStatus, long updateTime) {
this.id = id;
this.orderId = orderId;
this.shopName = shopName;
this.paidPrice = paidPrice;
this.updateTime = updateTime;
}
@Override
public String toString() {
return "OrderItem{" +
"id=" + id +
", orderId=" + orderId +
", shopName='" + shopName + '\'' +
", paidPrice=" + paidPrice +
", updateTime=" + updateTime +
'}';
}
}
}
二、核心代码
import com.aitogether.bigdata.onemetrics.runner.source.OrderItemSource;
import com.aitogether.bigdata.onemetrics.runner.source.OrderItemSource.OrderItem;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.OutputTag;
import java.time.Duration;
public class WindowWatermarkStrategy2 {
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1); // 并行度
// 接入数据源
DataStream<OrderItem> orderItemStream = env.addSource(new OrderItemSource())
// 配置生成Watermark方式,设置最大乱序时间5秒,时间戳按updateTime获取(此时系统按EventTime计算Watermark)
.assignTimestampsAndWatermarks(WatermarkStrategy
.<OrderItem>forBoundedOutOfOrderness(Duration.ofSeconds(5)) // 最大乱序时间(maxOutOfOrderness)
.withTimestampAssigner((event, timestamp) -> event.updateTime)); // 获取时间戳方式,内部会自动跟踪已观察到的最大时间戳
// 按orderId分区,开启一个10秒的滚动时间窗口,并计算窗口内的最大ID
orderItemStream.keyBy(element -> element.orderId)
.window(TumblingEventTimeWindows.of(Time.seconds(10))) // 滚动【事件时间】窗口
.reduce((a, b) -> a.id > b.id ? a : b) // 求窗口内最大ID
.print("result");
env.execute(WindowWatermarkStrategy2.class.getSimpleName());
}
}
三、结果分析
OrderItem{id=0, orderId=0, shopName='商品A', paidPrice=45.0, updateTime=1736238573687}
OrderItem{id=1, orderId=1, shopName='商品A', paidPrice=91.0, updateTime=1736238574692}
OrderItem{id=2, orderId=0, shopName='商品A', paidPrice=79.0, updateTime=1736238575696}
OrderItem{id=3, orderId=1, shopName='商品A', paidPrice=25.0, updateTime=1736238576699}
OrderItem{id=4, orderId=0, shopName='商品A', paidPrice=67.0, updateTime=1736238577701}
OrderItem{id=5, orderId=1, shopName='商品A', paidPrice=18.0, updateTime=1736238578706}
OrderItem{id=6, orderId=0, shopName='商品A', paidPrice=7.0, updateTime=1736238579710}
OrderItem{id=7, orderId=1, shopName='商品A', paidPrice=88.0, updateTime=1736238580714}
OrderItem{id=8, orderId=0, shopName='商品A', paidPrice=61.0, updateTime=1736238581719}
OrderItem{id=9, orderId=1, shopName='商品A', paidPrice=62.0, updateTime=1736238582724}
OrderItem{id=10, orderId=0, shopName='商品A', paidPrice=58.0, updateTime=1736238583726}
OrderItem{id=11, orderId=1, shopName='商品A', paidPrice=83.0, updateTime=1736238584729}
OrderItem{id=12, orderId=0, shopName='商品A', paidPrice=34.0, updateTime=1736238585732} // 12秒消息到达,此时Watermark:12-5=7
result> OrderItem{id=6, orderId=0, shopName='商品A', paidPrice=7.0, updateTime=1736238579710} // 触发7秒前的窗口计算,求出最大值6
result> OrderItem{id=5, orderId=1, shopName='商品A', paidPrice=18.0, updateTime=1736238578706} // 触发7秒前的窗口计算,求出最大值5
OrderItem{id=13, orderId=1, shopName='商品A', paidPrice=50.0, updateTime=1736238586738}
OrderItem{id=14, orderId=0, shopName='商品A', paidPrice=23.0, updateTime=1736238587743}
OrderItem{id=15, orderId=1, shopName='商品A', paidPrice=22.0, updateTime=1736238588747}
OrderItem{id=16, orderId=0, shopName='商品A', paidPrice=17.0, updateTime=1736238589752}
OrderItem{id=17, orderId=1, shopName='商品A', paidPrice=36.0, updateTime=1736238590758}
OrderItem{id=18, orderId=0, shopName='商品A', paidPrice=94.0, updateTime=1736238591763}
OrderItem{id=19, orderId=1, shopName='商品A', paidPrice=51.0, updateTime=1736238592768}
OrderItem{id=20, orderId=0, shopName='商品A', paidPrice=94.0, updateTime=1736238593773}
OrderItem{id=21, orderId=1, shopName='商品A', paidPrice=2.0, updateTime=1736238594778}
OrderItem{id=22, orderId=0, shopName='商品A', paidPrice=39.0, updateTime=1736238595782} // 22秒消息到达,此时Watermark:22-5=17
result> OrderItem{id=15, orderId=1, shopName='商品A', paidPrice=22.0, updateTime=1736238588747} // 触发17秒前的窗口计算,求出最大值15
result> OrderItem{id=16, orderId=0, shopName='商品A', paidPrice=17.0, updateTime=1736238589752} // 触发17秒前的窗口计算,求出最大值16
OrderItem{id=23, orderId=1, shopName='商品A', paidPrice=20.0, updateTime=1736238596784}
OrderItem{id=24, orderId=0, shopName='商品A', paidPrice=87.0, updateTime=1736238597790}
OrderItem{id=25, orderId=1, shopName='商品A', paidPrice=1.0, updateTime=1736238598794}
OrderItem{id=26, orderId=0, shopName='商品A', paidPrice=13.0, updateTime=1736238599797}
OrderItem{id=27, orderId=1, shopName='商品A', paidPrice=92.0, updateTime=1736238600801}
OrderItem{id=28, orderId=0, shopName='商品A', paidPrice=97.0, updateTime=1736238601804}
OrderItem{id=29, orderId=1, shopName='商品A', paidPrice=60.0, updateTime=1736238602806}
OrderItem{id=30, orderId=0, shopName='商品A', paidPrice=16.0, updateTime=1736238603811}
OrderItem{id=31, orderId=1, shopName='商品A', paidPrice=91.0, updateTime=1736238604813}
OrderItem{id=32, orderId=0, shopName='商品A', paidPrice=64.0, updateTime=1736238605817} // 后面数据以此类推
result> OrderItem{id=25, orderId=1, shopName='商品A', paidPrice=1.0, updateTime=1736238598794}
result> OrderItem{id=26, orderId=0, shopName='商品A', paidPrice=13.0, updateTime=1736238599797}
OrderItem{id=33, orderId=1, shopName='商品A', paidPrice=14.0, updateTime=1736238606821}
OrderItem{id=34, orderId=0, shopName='商品A', paidPrice=1.0, updateTime=1736238607825}
文档 https://apachecn.github.io/flink-doc-zh/#/docs/1.7-SNAPSHOT/README
Flink Watermark示例的更多相关文章
- [源码分析] 从源码入手看 Flink Watermark 之传播过程
[源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...
- Flink - watermark生成
参考,Flink - Generating Timestamps / Watermarks watermark,只有在有window的情况下才用到,所以在window operator前加上assig ...
- flink watermark介绍
转发请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/7610412.html 一 概念 watermark是flink为了处理eventTime窗口计算提 ...
- Apache Flink 入门示例demo
在本文中,我们将从零开始,教您如何构建第一个Apache Flink (以下简称Flink)应用程序. 开发环境准备 Flink 可以运行在 Linux, Max OS X, 或者是 Windows ...
- flink WaterMark之TumblingEventWindow
1.WaterMark,翻译成水印或水位线,水印翻译更抽象,水位线翻译接地气. watermark是用于处理乱序事件的,通常用watermark机制结合window来实现. 流处理从事件产生,到流经s ...
- 老板让阿粉学习 flink 中的 Watermark,现在他出教程了
1 前言 在时间 Time 那一篇中,介绍了三种时间概念 Event.Ingestin 和 Process, 其中还简单介绍了乱序 Event Time 事件和它的解决方案 Watermark 水位线 ...
- [白话解析] Flink的Watermark机制
[白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...
- Flink - FlinkKafkaConsumer010
Properties properties = new Properties(); properties.setProperty("bootstrap.servers", &quo ...
- Flink源码分析
http://vinoyang.com/ http://wuchong.me Apache Flink源码解析之stream-source https://yq.aliyun.com/articles ...
- Flink Program Guide (5) -- 预定义的Timestamp Extractor / Watermark Emitter (DataStream API编程指导 -- For Java)
本文翻译自Pre-defined Timestamp Extractors / Watermark Emitter ------------------------------------------ ...
随机推荐
- mybatis-plus.global-config.db-config.id-type=auto 和 @TableId(value = "id", type = IdType.ASSIGN_ID)哪个优先生效
对于id自动生成的方式,有注解和配置两种. 含义相同:不过设置自动增长的时候必须保证数据库中id是自增,assign_id和assign_uuid则不需要. yml配置: mybatis-plus: ...
- 详细介绍Dubbo的SPI机制
一.定义 Dubbo 的 SPI (Service Provider Interface) 机制是对 Java 原生 SPI 机制的增强和扩展,提供了更强大的扩展能力 二.Dubbo SPI 核心实现 ...
- DP刷题总结-2
同步于Luogu blog T1 AT_joisc2007_buildi ビルの飾り付け (Building) 简化题意 最长上升子序列模板 分析 \(O(n^2)\)做法 考虑DP 定义状态:\(d ...
- FastJSON序列化扩展接口与特性详解
结论先行 FastJSON 的 SerializeFilter 接口通过 动态拦截和修改序列化过程,可实现字段名重命名.敏感数据脱敏.字段过滤等高级功能.其核心子接口包括 PropertyPreFil ...
- 119K star!无需GPU轻松本地部署多款大模型,DeepSeek支持!这个开源神器绝了
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 "只需一行命令就能在本地运行Llama 3.DeepSeek-R1等前沿大模型,支 ...
- Linux还能拯救U盘???---U盘的起死回生
作死;): 今天U盘在处理某些东西的时候,我性子急,直接把进程结束了,然后,就悲剧了( ̄ 'i  ̄;) 插到电脑上,一插就卡,一点就未响应,未响应.... PE系统打开还是老样子... 右键想格式化, ...
- 最新Typora1.9.5破解版下载与使用教程(Windows+Mac)
一.Typora是什么? 一款 Markdown 编辑器和阅读器,能知道Typora的小伙伴,肯定也会用的 二.使用步骤 1.下载软件 夸克网盘:https://pan.quark.cn/s/2d6d ...
- 【SQL周周练】给你无酸纸、变色油墨,你能伪造多少美金?
大家好,我是"蒋点数分",多年以来一直从事数据分析工作.从今天开始,与大家持续分享关于数据分析的学习内容. 本文是第 2 篇,也是[SQL 周周练]系列的第 2 篇.该系列是挑选或 ...
- Vue之“表单修饰符”
1.lazy:失去焦点时处理 案例1 2.number:限制只能输入数字 案例1 3.trim:去掉前后空格 案例1
- Odoo14前端框架常用操作
单页Web应用(single page web application,SPA): SPA 是一种特殊的 Web 应用,是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的. 它将所有的 ...