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 ------------------------------------------ ...
随机推荐
- 阿里云服务器中Linux下centos7.6安装mysql8.0.11
1.下载安装 MySQL最新下载地址:https://dev.mysql.com/downloads/mysql/ 选择的是Linux 64位通用的二级制版本,这样不在需要进行编译安装,系统安装依赖 ...
- 🎀springboot banner介绍及使用
简介 Banner是指应用程序启动时显示的信息.对于Spring Boot应用来说,默认情况下,当你启动一个 Spring Boot应用时,控制台上会打印出一段由 Spring Boot自带的ASCI ...
- Java 中常见的垃圾收集器有哪些?
Java 中常见的垃圾收集器 Java 提供了多种垃圾收集器(Garbage Collector, GC),每种收集器针对不同的应用场景和需求进行了优化.以下是常见的垃圾收集器及其特点. 1. Ser ...
- UT
Mockito 官网 注解
- 记录一次SpringBoot + Vue前后分离项目的部署流程
前言 本教程使用黑马 SpringBoot3+Vue3全套视频教程 大事件项目作为前后端代码. 前置需要: mysql jdk redis nginx linux环境 打包 前端 构建项目命令 npm ...
- <HarmonyOS第一课09>应用程序框架进阶#鸿蒙课程##鸿蒙生态#
课程介绍 本课程<应用程序框架进阶>旨在深入探讨应用程序框架的核心概念和高级特性.课程首先介绍应用程序框架的基本概念,确保学员对框架有全面的认识.接着,我们将深入探讨AbilityStag ...
- rollup.js:下一代 JS模块打包工具解析器
引言 在互联网技术领域,不断涌现的新技术和新理念为开发者提供了无限的可能.本文将深入探讨一系列技术话题,旨在帮助读者更好地理解这些技术,并应用于实际开发中.接下来,我们将逐步展开各个主题的讨论. 2. ...
- 信息资源管理综合题之“如何利用PKI实现身份认证和抗抵赖和防篡改等安全措施 ”
一.A企业在网上招标采购某种原材料,B是某个参与招标供应商 1.请讨论如何利用PKI(公钥基础设施),实现A企业接收B报价过程的身份认证.抗抵赖和防篡改等安全措施 二.答案 1.请讨论如何利用PKI( ...
- 信息资源管理综合题之“QS认证是什么标准 和 如何证明已通过QS 和 可否建立自己的生产标准”
一.案例:自2003年起,我国开始对大米.食用植物油等食品进行了一种新的管理制度:食品质量安全市场准入制度,到目前为止,所有经过加工的食品,生产地址在国内的产品全部必须申请生产许可证,经过强制性的检验 ...
- TVM Pass优化 -- InferType 类型推导
定义(What) InferType,类型推断,顾名思义,给表达式进行类型的推断 直接上代码 import tvm from tvm import relay import numpy as np d ...