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示例的更多相关文章

  1. [源码分析] 从源码入手看 Flink Watermark 之传播过程

    [源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...

  2. Flink - watermark生成

    参考,Flink - Generating Timestamps / Watermarks watermark,只有在有window的情况下才用到,所以在window operator前加上assig ...

  3. flink watermark介绍

    转发请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/7610412.html 一 概念 watermark是flink为了处理eventTime窗口计算提 ...

  4. Apache Flink 入门示例demo

    在本文中,我们将从零开始,教您如何构建第一个Apache Flink (以下简称Flink)应用程序. 开发环境准备 Flink 可以运行在 Linux, Max OS X, 或者是 Windows ...

  5. flink WaterMark之TumblingEventWindow

    1.WaterMark,翻译成水印或水位线,水印翻译更抽象,水位线翻译接地气. watermark是用于处理乱序事件的,通常用watermark机制结合window来实现. 流处理从事件产生,到流经s ...

  6. 老板让阿粉学习 flink 中的 Watermark,现在他出教程了

    1 前言 在时间 Time 那一篇中,介绍了三种时间概念 Event.Ingestin 和 Process, 其中还简单介绍了乱序 Event Time 事件和它的解决方案 Watermark 水位线 ...

  7. [白话解析] Flink的Watermark机制

    [白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...

  8. Flink - FlinkKafkaConsumer010

    Properties properties = new Properties(); properties.setProperty("bootstrap.servers", &quo ...

  9. Flink源码分析

    http://vinoyang.com/ http://wuchong.me Apache Flink源码解析之stream-source https://yq.aliyun.com/articles ...

  10. Flink Program Guide (5) -- 预定义的Timestamp Extractor / Watermark Emitter (DataStream API编程指导 -- For Java)

    本文翻译自Pre-defined Timestamp Extractors / Watermark Emitter ------------------------------------------ ...

随机推荐

  1. 阿里云服务器中Linux下centos7.6安装mysql8.0.11

    1.下载安装 MySQL最新下载地址:https://dev.mysql.com/downloads/mysql/  选择的是Linux 64位通用的二级制版本,这样不在需要进行编译安装,系统安装依赖 ...

  2. 🎀springboot banner介绍及使用

    简介 Banner是指应用程序启动时显示的信息.对于Spring Boot应用来说,默认情况下,当你启动一个 Spring Boot应用时,控制台上会打印出一段由 Spring Boot自带的ASCI ...

  3. Java 中常见的垃圾收集器有哪些?

    Java 中常见的垃圾收集器 Java 提供了多种垃圾收集器(Garbage Collector, GC),每种收集器针对不同的应用场景和需求进行了优化.以下是常见的垃圾收集器及其特点. 1. Ser ...

  4. UT

    Mockito 官网 注解

  5. 记录一次SpringBoot + Vue前后分离项目的部署流程

    前言 本教程使用黑马 SpringBoot3+Vue3全套视频教程 大事件项目作为前后端代码. 前置需要: mysql jdk redis nginx linux环境 打包 前端 构建项目命令 npm ...

  6. <HarmonyOS第一课09>应用程序框架进阶#鸿蒙课程##鸿蒙生态#

    课程介绍 本课程<应用程序框架进阶>旨在深入探讨应用程序框架的核心概念和高级特性.课程首先介绍应用程序框架的基本概念,确保学员对框架有全面的认识.接着,我们将深入探讨AbilityStag ...

  7. rollup.js:下一代 JS模块打包工具解析器

    引言 在互联网技术领域,不断涌现的新技术和新理念为开发者提供了无限的可能.本文将深入探讨一系列技术话题,旨在帮助读者更好地理解这些技术,并应用于实际开发中.接下来,我们将逐步展开各个主题的讨论. 2. ...

  8. 信息资源管理综合题之“如何利用PKI实现身份认证和抗抵赖和防篡改等安全措施 ”

    一.A企业在网上招标采购某种原材料,B是某个参与招标供应商 1.请讨论如何利用PKI(公钥基础设施),实现A企业接收B报价过程的身份认证.抗抵赖和防篡改等安全措施 二.答案 1.请讨论如何利用PKI( ...

  9. 信息资源管理综合题之“QS认证是什么标准 和 如何证明已通过QS 和 可否建立自己的生产标准”

    一.案例:自2003年起,我国开始对大米.食用植物油等食品进行了一种新的管理制度:食品质量安全市场准入制度,到目前为止,所有经过加工的食品,生产地址在国内的产品全部必须申请生产许可证,经过强制性的检验 ...

  10. TVM Pass优化 -- InferType 类型推导

    定义(What) InferType,类型推断,顾名思义,给表达式进行类型的推断 直接上代码 import tvm from tvm import relay import numpy as np d ...