Flink的时间语义与水印(WaterMark)

Flink在实时处理中采用事件时间确保准确性,而非处理时间。水印(WaterMark)机制用于处理乱序事件,保证数据正确进入窗口。水印生成器如BoundedOutOfOrdernessWatermarks以最大延迟为基准生成水印,防止过早关闭窗口。当数据通道无数据时,水印更新受阻,可能影响下游汇总水印。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Flink的时间语义与水印(WaterMark)

在实时处理中,由于数据的产生时间与消费时间是无法做到一致的,如果使用处理时间来进行业务逻辑的判断,实际上是无法保证做到数据的准确性的。这体现在以下几个方面:

  • 事件发生于2:59,而程序处理时已经是3:00,对事件的统计将会计入到3:00开始的窗口
  • flink出现故障,两个小时后恢复时,需要消费这两个小时内新产生的数据,这些数据会全部进入到flink重新启动后的窗口
  • flink按递增顺序给数据标号,而重启后flink数据与重启前数据顺序是不同的,导致标号不同

所以,实际上来说,以处理时间来进行实时计算是不准确以及具有很大限制的。以逻辑判断来说,三点到五点的数据就应该是事件发生在三点到五点之间的数据,而不是在三点到五点之间进行处理的数据。

但使用事件时间时,我们必须考虑两个问题,由于数据的到来是动态无界的,我们无法获取到所有的数据的时间戳;由于网络延迟,数据的到来顺序也是乱的,我们无法保证截至某一条数据,以后就再也没有该时间段的数据。所以我们需要一个水印机制,一个水印表示,数据流中的事件时间已经达到了水印标识的时间,数据流中不应该出现时间戳小于该水印的时间戳的数据。

水印会根据数据的时间戳而更新,当水印时间戳达到某个窗口的开启时间后,该窗口被开启,数据进入窗口中,同样的,当水印时间戳达到某个窗口的关闭时间后,该窗口被关闭。

如果数据流是有序的,很容易想到只要以窗口内最大数据的时间戳为水印的时间戳即可保证数据流中不会出现时间戳小于水印时间戳的数据。

当数据流是无序的,时间戳较小的数据可能在时间戳较大的数据的后面,可以指定水印时间戳为数据最大时间戳减去最大可能延迟的时间,以保证数据的迟到时间如果在该延迟时间内,窗口并没有关闭,该数据仍会被纳入到该窗口的计算当中。

水印生成器

所有的水印生成器都需要实现WatermarkGenerator接口,该接口定义了更新水印的策略。

两个方法:

// 每收到一个数据触发
void onEvent(T event, long eventTimestamp, WatermarkOutput output);
// 每隔指定时间触发,更新水印
void onPeriodicEmit(WatermarkOutput output);

常用BoundedOutOfOrdernessWatermarks,该类实现了WatermarkGenerator接口,定义了更新水印的方法。

 private long maxTimestamp;
 private final long outOfOrdernessMillis;
// 对每个数据进行比较,取最大时间戳赋给maxTimestamp;
  @Override
    public void onEvent(T event, long eventTimestamp, WatermarkOutput output) {
        maxTimestamp = Math.max(maxTimestamp, eventTimestamp);
    }
// 创建新的水印,为当前最大时间戳减去指定的延迟时间
    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        output.emitWatermark(new Watermark(maxTimestamp - outOfOrdernessMillis - 1));
    }
// 构造器,用于初始化水印生成器,maxOutOfOrderness为用户指定的延迟时间
public BoundedOutOfOrdernessWatermarks(Duration maxOutOfOrderness) {
    this.maxTimestamp = Long.MIN_VALUE + outOfOrdernessMillis + 1;
    }

水印生成器每隔一段时间调用onPeriodicEmit方法更新水印,该事件间隔默认为200ms,可以通过以下方法指定。

// 指定水印生成间隔为100ms
environment.getConfig().setAutoWatermarkInterval(100);

其他

由于水印的生成是基于数据的时间戳的,如果某通道中久久没有数据,其水印会无法更新,当下游汇总上游的水印时,会以最低水印时间戳为准。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值