Flink 时间属性深度解析

前言

Flink 的 API 大体上可以划分为三个层次:最底层的 ProcessFunction、中间一层的 DataStream API 和最上层的 SQL / Table API,这三层的每一层都非常依赖于时间属性。
在这里插入图片描述

Flink 时间语义

Flink 支持的核心时间语义是 Processing TimeEvent Time。两者的不同点如下表所示:

Processing Time(处理时间) Event Time(事件时间)
真实世界的时间 数据世界的时间
处理数据节点的本地时间 数据本身携带的TimeStamp
处理简单 处理复杂
结果不确定(无法重现) 结果确定(可重现)

在判断应该使用 Processing Time 还是 Event Time 时,可以遵循一个原则:当你的程序遇到某个问题要从上一个 checkpoint 或者 savepoint 进行重启时,是否希望结果完全相同

  • 希望结果完全相同,就只能用 Event Time。
  • 如果接受结果不同,则可以用 Processing Time。

Processing Time 的一个常见的用途是,根据现实时间来统计整个系统的吞吐,比如要计算现实时间一个小时处理了多少条数据,这种情况只能使用 Processing Time。

注意:当使用每小时 Processing Time 时间窗口时,窗口包括在系统时钟指示整点之间的数据。例如:一个程序在 9:15 开始运行,则第一个每小时处理时间窗口将包括在 9:15 和 10:00 之间处理的事件,下一个窗口将包括在 10:00 和 11:00 之间处理的事件。

时间的特性

对于 Processing Time:因为使用的是本地机器节点的时间,所以每一次取到的 Processing Time 肯定都是递增的,相当于是一个有序的数据流。

对于 Event Time:因为时间是绑定在每一条数据上,由于网络延迟、程序内部逻辑等等原因,数据的时间可能会存在乱序的情况。
在这里插入图片描述
解决 Event Time 乱序的问题就需要使用 Watermark。
一个 Watermark 本质上就是一个 timestamp 数值,表示以后到来的数据已经再也没有小于或等于这个时间的了。

Watermark(t) 表示数据流中 “ event time =< t ” 的数据都已到达,流中不应该有 “ 时间戳 <= t ” 的数据。

事实上,Watermark(t) 发生之后,还会出现很多 “ 时间戳 <= t ” 的数据。这些数据称为 Lateness(迟到数据)。

Timestamp 和 Watermark 行为概览

在这里插入图片描述

1、Timestamp 分配和 Watermark 生成

WatermarkGenerator 是 Watermark 的生成器,接口代码如下:

// 可以基于事件或者周期性的生成 watermark
@Public
public interface WatermarkGenerator<T> {
   
   
    // 每来一条数据调用一次,可检查或记录事件的时间戳,或基于事件本身去生成watermark
    void onEvent(T event, long eventTimestamp, WatermarkOutput output);
    // 周期性调用,可能会生成新的watermark,有可能不会。
    // 不会生成watermark是因为上一个watermark还没有触发。
    // 调用此方法生成watermark的间隔时间由ExecutionConfig.getAutoWatermarkInterval()决定。
    void onPeriodicEmit(WatermarkOutput output);
}

1.1 Watemark 的生成方式有两种:

1、周期性生成
通常通过 onEvent() 观察传入的事件数据,然后定期调用 onPeriodicEmit() 发出 Watemark。
调用此方法生成 watermark 的间隔时间由 ExecutionConfig.getAutoWatermarkInterval() 决定。
当调用 onPeriodicEmit() 方法时,如果返回的 watermark 非空并值大于前一个 watermark,则将发出新的 watermark。

// 该 watermark 生成器可以覆盖的场景是:数据源在一定程度上乱序。
public class BoundedOutOfOrdernessGenerator implements WatermarkGenerator<MyEvent> {
   
   
    private final long maxOutOfOrderness = 3500; // 3.5 秒
    private long currentMaxTimestamp;

    @Override
    public void onEvent(MyEvent event, long eventTimestamp, WatermarkOutput output) {
   
   
        currentMaxTimestamp = Math.max(currentMaxTimestamp, eventTimestamp);
    }

    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
   
   
        // 发出的 watermark = 当前最大时间戳 - 最大乱序时间
        output.emitWatermark(new Watermark(currentMaxTimestamp - maxOutOfOrderness - 1));
    }
}

2、标记生成
查看 onEvent() 中的事件数据,并等待流中携带 Watermark 的特殊标记事件或打点数据。当获取到这些数据时,它就会发出 Watermark。

通常情况下,标记生成器不会通过 onPeriodicEmit() 方法发出 watermark。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值