一文带你搞懂Flink Watermark

1、Watermark的介绍

首先我们应该了解一个概念,就是Watermark是用来测量时间的进度的一种方法。 因为我们在使用EventTime时间来进行计算的时候,由于EventTime是真实世界的时间,那么百分之100可能会发生乱序数据,那么何为乱序数据呢,也就是说,我1分钟前产生的数据现在才进入到我的系统中进行处理,这里就是延迟数据,那么乱序就是在正常的时间数据流中夹杂着一些非顺序的一些数据,例如某台机器的网络抖动,或者网卡和系统的延迟导致了这台机器上报的数据延迟上传,那么flink在处理的时候,这个时候可能收到了现在的数据也可能收到了10秒或者更长的数据,这个就是乱序数据。那么watermark就是用来测量乱序数据的进度,也就是说watermark用来触发计算,或者触发一些操作。Watermark是一种特殊的数据!

2、Watermark的运行原理

2.1 核心原理

我们首先要有一个场景来进行讲解这个事情,那么我们就看看我们的场景:

我们有一个5s的窗口,并且我们可以容忍的延迟时间为2s。那么也就是在7s的时候会触发计算,我们往下看就明白为什么会7s触发计算,或者永不触发

单task,单分区的时候。其中的33 是数据, 2 是他携带的时间戳在右侧有一个5秒的窗口

image-20210528162059671

那么我们的watermark的计算公式就是 watermark = time - latertime 。那么这个时候我们可以得到这个watermark是0,那么他属于0-5s的窗口,那么我们就放到窗口里面去。

image-20210528162301787

这个时候又来了一条数据,就会变成下面这样对吧,为什么会变成两个窗口呢,因为99这条数据并不属于0-5秒这个窗口里面,因为flink窗口的大小是包左不包右的,那么这个时候我们大家应该也明白了,数据都是放在那里的,数据放在哪个桶或者说窗口是根据eventtime来决定的。

image-20210528163448351

这个时候来了一条乱序数据,那么我们的watermark怎么更新呢?
image-20210528163727462我们可以看到我花的图 其中,23数据携带的时间戳是3,watermark也是3,那么这个时候明显违背了我们的

公式计算规则啊,其实不是的,watermark更新是有条件的,那就是watermark 不能倒着走啊,因为他是负责测量数据的进度的。

所以他的watermark 并不会按照公式计算,而是采用的上一个watermark。

那么我们多插几条数据看看。

image-20210528164021873

那么这个时候我们并没有触发我们的窗口计算,那么窗口计算什么时候触发呢,当watermark大于等于窗口触发时间。

也就是大于等于5的时候触发计算。

image-20210528164209329

那么我们讲到这里,应该大部分人都能够了解到了watermark的运行机制,以及窗口什么时候计算。

那么我们接下来就来考虑一下我们的多并行度下,我们的watermark如何传递?

2.2 Watermark的传递机制

我们应该知道 在一个 task中有很多的subtask,那么这些subtask都有自己的watermark,这个时候就会涉及到 watermark的传递,因为下游也是依赖这些watermark的。那就让我们看看watermark的传递机制吧。

image-20210528180726375

我们可以看到Watermark在顺序的向下游流动,左侧的向右箭头,就是这个意思。那么我们这个时候发现有一个Partition WM 这个其实就是各个分区的 SubTask的Watermark,我这个时候发现,每个subtask的watermark都是不一样的,并且task会存储这些watermark,记录下来各个分区的watermark,并且把最小的watermark广播出去,因为当前还没有记录的是2、4、3、6,其中2是最小的。

image-20210528190609888

这个时候当传递过来的watermark4 更新了,那么这个时候我们就将最小的3传递出去

image-20210528190714968

当7这个watermark传递过来的时候,我们就会发现,传递过去的依然是最小的3。

那么这个时候我想大家对watermark应该是比较了解了。

3、watermark怎么用

1、常见用法

WatermarkStrategy
        .<Tuple2<Long, String>>forBoundedOutOfOrderness(Duration.ofSeconds(20))
        .withTimestampAssigner((event, timestamp) ->timestamp);

2、WatermarkGenerator

/**
 * {@code WatermarkGenerator} 可以基于事件或者周期性的生成 watermark。
 *
 * <p><b>注意:</b>  WatermarkGenerator 将以前互相独立的 {@code AssignerWithPunctuatedWatermarks} 
 * 和 {@code AssignerWithPeriodicWatermarks} 一同包含了进来。
 */
@Public
public interface WatermarkGenerator<T> {

    /**
     * 每来一条事件数据调用一次,可以检查或者记录事件的时间戳,或者也可以基于事件数据本身去生成 watermark。
     */
    void onEvent(T event, long eventTimestamp, WatermarkOutput output);

    /**
     * 周期性的调用,也许会生成新的 watermark,也许不会。
     *
     * <p>调用此方法生成 watermark 的间隔时间由 {@link ExecutionConfig#getAutoWatermarkInterval()} 决定。
     */
    void onPeriodicEmit(WatermarkOutput output);
}

3、watermark 分区数据倾斜解决方案

在数据源直接使用时如果因为数据源中的某一个分区/分片在一段时间内未发送事件数据,则意味着watermarkStrategy也不会获得任何数据去生成watermark,在这种情况下可以通过设置有一个空闲时间,当超过这个时间则将这个分片或分区标记为空闲状态。

WatermarkStrategy
        .<Tuple2<Long, String>>forBoundedOutOfOrderness(Duration.ofSeconds(20))
        .withIdleness(Duration.ofMinutes(1));//当时间超过1分钟则设置为空闲状态 
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值