watermark(水印)

Flink中用于衡量event time进度的机制叫做水印

官方定义

watermark流(水印流)作为数据流的一部分,并带有一个时间戳t,当watermark t声明event time达到了t时刻,表名该数据流中不存在时间戳t`<= t的元素

对于watermark的理解

在下文中的例子中,我们有一个带有时间戳的事件流,但是由于某种原因它们并不是按顺序到达的。图中的数字代表事件发生的时间戳。第一个到达的事件发生在时间 4,然后它后面跟着的是发生在更早时间(时间 2)的事件,以此类推:

warter_mark

注意这是一个按照事件时间处理的例子,这意味着时间戳反映的是事件发生的时间,而不是处理事件的时间。事件时间(Event-Time)处理的强大之处在于,无论是在处理实时的数据还是重新处理历史的数据,基于事件时间创建的流计算应用都能保证结果是一样的。

现在假设我们正在尝试创建一个流计算排序算子。也就是处理一个乱序到达的事件流,并按照事件时间的顺序输出事件。

理解1

数据流中的第一个元素的时间是 4,但是我们不能直接将它作为排序后数据流的第一个元素并输出它。因为数据是乱序到达的,也许有一个更早发生的数据还没有到达。事实上,我们能预见一些这个流的未来,也就是我们的排序算子至少要等到 2 这条数据的到达再输出结果。

有缓存,就必然有延迟。

理解2

如果我们做错了,我们可能会永远等待下去。首先,我们的应用程序从看到时间 4 的数据,然后看到时间 2 的数据。是否会有一个比时间 2 更早的数据到达呢?也许会,也许不会。我们可以一直等下去,但可能永远看不到 1 。

最终,我们必须勇敢地输出 2 作为排序流的第一个结果。

理解3

我们需要的是某种策略,它定义了对于任何带时间戳的事件流,何时停止等待更早数据的到来。

这正是 watermark 的作用,他们定义了何时不再等待更早的数据。

Flink 中的事件时间处理依赖于一种特殊的带时间戳的元素,成为 watermark,它们会由数据源或是 watermark 生成器插入数据流中。具有时间戳 t 的 watermark 可以被理解为断言了所有时间戳小于或等于 t 的事件都(在某种合理的概率上)已经到达了。

何时我们的排序算子应该停止等待,然后将事件 2 作为首个元素输出?答案是当收到时间戳为 2(或更大)的 watermark 时。

理解4

我们可以设想不同的策略来生成 watermark。

我们知道每个事件都会延迟一段时间才到达,而这些延迟差异会比较大,所以有些事件会比其他事件延迟更多。一种简单的方法是假设这些延迟不会超过某个最大值。Flink 把这种策略称作 “有界无序生成策略”(bounded-out-of-orderness)。当然也有很多更复杂的方式去生成 watermark,但是对于大多数应用来说,固定延迟的方式已经足够了。

Flink中的时间

Event Time

事件时间指事件在设备上的发生时间,该时间通常在消息进入Flink之前发生,且该事件发生的时间戳可以从每条记录单独提取

Ingestion Time(摄取时间)

摄取时间指的是消息进入flink的时间

Processing Time

处理时间指的是执行某个任务时的系统时间,在消息进入flink且被window处理时发生

三种时间关系示意图

times_clocks