Flink 1.19 Watermark源码分析

Watermark

  • watermark用于指示事件的进展,一个时间戳为T的watermark表示事件时间已经推进到了T,而且不会有比T更早的事件出现
  • watermark一般在数据流的源头创建,并通过流和操作符传播
  • 当到达流的末尾是,会发出一个Long.MAX_VALUE表示终止水印

前提

所有算子包括Source和Sink都是逻辑数据流图,需要StreamGraphGenerator和JobGraphGenerator生成物理执行计划,根据information通过translator将算子转为operator。也就是说,flink job的编码是两条线,一条明线,即用户编写的逻辑,一条暗线是flink内部真正封装了算子行为,水位线传递,Checkpoint生成逻辑的物理执行计划。

watermark的源头

  • TimestampsAndWatermarks是source从事件提取时间戳生成watermark的重要接口
  • WatermarkUpdateListener接口用于监听
  • createMainOutput 创建ReaderOutput,用于Source Reader输出数据,包含内部处理时间戳逻辑和watermark生成逻辑
  • startPeriodicWatermarkEmits和stopPeriodicWatermarkEmits 启动和停止周期性watermark生成
  • emitImmediateWatermark 立即发出watermark
  • 两个工厂方法createProgressiveEventTimeLogic和createNoOpEventTimeLogic ,会根据 WatermarkStrategy 生成TimestampsAndWatermarks实例
    • createProgressiveEventTimeLogic 创建一个符合渐进式事件时间逻辑的TimestampsAndWatermarks 实例,用于流处理
    • createNoOpEventTimeLogic 创建一个无操作的TimestampsAndWatermarks 实例,用于批处理,跳过watermark生成逻辑
  • 接口TimestampsAndWatermarks被ProgressiveTimestampsAndWatermarks和 NoOpTimestampsAndWatermarks实现,他们唯一的创建方式是调用TimestampsAndWatermarks的工程方法创建
  • 那么,是谁创建了TimestampsAndWatermarks了呢,是SourceOperator,Source在物理计划的实现。在SourceOperator的open方法创建了eventTimeLogic,可以看到watermarkStrategy代表用户指定的生成策略,我们指定的BoundedOutOfOrdernessWatermarks策略就是在这里被传递进物理执行计划的
  • 话分两头,SourceOperator需要具有将record和watermark输出的能力,Source的输出由ReaderOutput 定义,他实现了SourceOutput 能力,是SourceReader和下游算子交互的核心接口之一
  • 数据记录发送
    • collect(T record) 发送不带时间戳的记录
    • collect(T record, long timestamp) 发送带时间戳的记录
  • watermark发送,emitWatermark(Watermark watermark) 发送watermark,标记事件进展
  • idle状态管理,markIdle() 标记当前输出为idle状态,表示下游算子无需等待该输出的watermark
  • split管理
    • createOutputForSplit(String splitId) 为特定分片创建一个独立的SourceOutput ,用于设置各个分片的创建逻辑,比如创建水位线
    • releaseOutputForSplit(String splitId) 释放特定分片的SourceOutput
  • SourceOperator 中,output就是成员对象currentMainOutput,他被上文eventTimeLogic所创建,eventTimeLogic 是TimestampsAndWatermarks类型,当我们使用流处理时,eventTimeLogic的类型是ProgressiveTimestampsAndWatermarks
  • ProgressiveTimestampsAndWatermarks实现了createMainOutput方法,在这个方法中currentMainOutput被赋值为StreamingReaderOutput
  • StreamingReaderOutput继承自SourceOutputWithWatermarks,SourceOutputWithWatermarks实现了SourceOutput
  • 现在我们就知道了一些事情,SourceOperator有两个成员变量,类型为TimestampsAndWatermarks和ReaderOutput,TimestampsAndWatermarks用于创建流处理或者批处理的Watermark,根据用户指定watermark生成策略激发新的watermark,以及创建ReaderOutput,ReaderOutput用于向下游发送record和watermark

watermark生成

  • WatermarkGenerator有两个方法onEvent 和onPeriodicEmit
  • onEvent表示record到达时,检查或者记住这个时间戳,参数里包含WatermarkOutput,可以决定是否发出watermark
  • onPeriodicEmit 周期性发射水印
  • 以BoundedOutOfOrdernessWatermarks为例,record到达之后会调用onEvent记住record的时间戳,然后当onPeriodicEmit触发的时候发射record时间戳减延迟时间作为watermark

watermark传递(KeyedCoProcessFunction为例)

  • 一个用户可以使用或者继承的算子都有他对应的运行时operator,负责执行用户算子的逻辑,并管理状态,传递watermark。比如KeyedCoProcessFunction对应KeyedCoProcessOperator。
  • KeyedCoProcessOperatorimplementTwoInputStreamOperator,TwoInputStreamOperator里面具有接口函数processWatermark1和processWatermark2,但是KeyedCoProcessOperator并没有实现这两个的方法,他的默认实现被放到了父类的父类中。
  • AbstractUdfStreamOperator 是用户定义function对应的operator的基类,KeyedCoProcessOperator继承了AbstractUdfStreamOperator 。
  • AbstractUdfStreamOperator继承了AbstractStreamOperator ,AbstractStreamOperator是所有stream operator的基类。里面定义了两个方法processWatermark1和 processWatermark2
    • 处理watermark的逻辑是,处理指定的输入流的watermark,对于这个两输入的算子,就有两个索引,然后更新这个算子的watermark状态,更新时间服务管理器并发射watermark到下游
    • 其中updateWatermark是关键的方法,他会遍历所有输入方向的watermark,然后取其中小的watermark,更新为这个算子的combine watermark。如果所有输入都是idle,那这个算子也会变为idle状态
    • 如果成功更新了combine watermark,会将这个新的combine watermark更新时间管理服务以及发射这个watermark。这涉及两个东西InternalTimeServiceManager和Output<StreamRecord<OUT>>
    • InternalTimeServiceManager 太大了,就不说了
    • 这里的Output 其实是WatermarkOutput,他有多种实现,有非链式算子输出和链式算子输出
      • 如果是非链式算子会将watermark写入网络缓冲区,通过网络发给下游算子
      • 如果是链式算子会直接将watermark传递给下游算子
  • IndexedCombinedWatermarkStatus 通过索引管理多个输入流的PartialWatermark,利用CombinedWatermarkStatus计算全局watermark(也就是这个算子对应的operator),它是对CombinedWatermarkStatus的封装,添加了按索引管理输入流的功能
  • CombinedWatermarkStatus 组合多个PartialWatermark对象,计算全局watermark值和状态,他维护了一个PartialWatermark列表
    • updateWatermark是更新watermark的关键方法,取小的那个watermark
  • PartialWatermark表示单个输入流的watermark状态
    • 每个PartialWatermark跟踪一个输入流的watermark值和idle,active状态。
    • onWatermarkUpdate表示收到watermark变动时应该做什么动作,这个动作在PartialWatermark初始化的时候会指定
  • WatermarkOutputMultiplexer(watermark输出多路复用器)
    • WatermarkUpdateListener用来监听某个输入流的watermark值,发生变化时会调用onWatermarkUpdate方法
    • 在WatermarkOutputMultiplexer中当某个输入流watermark更新时,WatermarkOutputMultiplexer会通过WatermarkUpdateListener将更新传递到底层的WatermarkOutput
    • WatermarkOutputMultiplexer将多个输入流的watermark更新组合成一个全局的watermark更新。
    • 支持两种类型的输入:立即输出和延迟输出
相关推荐
starzy19903 小时前
Flink 优化之网络缓存优化及参数详解:从数据传输机制到反压原理的生产调优指南
网络·缓存·flink
智码看视界1 天前
Edge AI 全栈实战 ④:向量数据库 + RAG 让 IoT 诊断拥有“记忆“
flink·向量数据库·rag·全栈开发·edgeai·iot诊断
starzy19902 天前
Flink 优化之 CheckPoint 优化及参数详解:从原理到生产环境调优的完整指南
大数据·flink
nvd112 天前
深入解构 Flink FLIP-27 数据摄取内核:从 env.execute() 到工业级 Source 运行机制
大数据·flink
nvd113 天前
Flink 极简入门与零常驻批处理架构实战:从双模式辨析到 GitOps 通用模具治理
大数据·架构·flink
俊哥大数据3 天前
Flink1.20.3 实时消费 Kafka 数据并解析入湖 Paimon1.4.2 全流程实战
分布式·flink·kafka·数据湖·paimon
TLA技术4 天前
LogMiner vs 裸日志解析(六):想提速,只能“堆实例”,结果把源库拖垮
数据库·oracle·flink·dba·迁移学习
EatFan4 天前
从T+1到分钟级:湖仓一体在大厂的真实落地收益对照(携程/网易云信/腾讯)
starrocks·flink·硬件架构·doris·湖仓一体·paimon
用户3610588626125 天前
Flink Keyed Window 详解及代码实现:从并行计算原理到数据倾斜优化
大数据·flink
starzy199011 天前
Flink Sliding Window 详解及代码实现:从窗口重叠到状态爆炸防控
运维·数据库·flink