Flink Time

2020-05-04  本文已影响0人  专职掏大粪

Flink 时间语义

事件特性

对于 Processing Time,因为我们是使用的是本地节点的时间,我们每一次取到的 Processing Time 肯定都是递增的,递增就代表着有序,所以说我们相当于拿到的是一个有序的数据流。

而在用 Event Time 的时候因为时间是绑定在每一条的记录上的,由于网络延迟、程序内部逻辑、或者其他一些分布式系统的原因,数据的时间可能会存在一定程度的乱序。在 Event Time 场景下,我们把每一个记录所包含的时间称作 Record Timestamp。如果 Record Timestamp 所得到的时间序列存在乱序,我们就需要去处理这种情况。

这个时候我们在整个时间序列里插入一些类似于标志位的一些特殊的处理数据,这些特殊的处理数据叫做 watermark。一个watermark 本质上就代表了这个 watermark 所包含的 timestamp 数值,表示以后到来的数据已经再也没有小于或等于这个时间的了

Timestamp 分配和 Watermark 生成

Flink 支持两种 watermark 生成方式。

通过 collectWithTimestamp 方法发送一条数据,其中第一个参数就是我们要发送的数据,第二个参数就是这个数据所对应的时间戳;也可以调用 emitWatermark 方法去产生一条 watermark,表示接下来不会再有时间戳小于等于这个数值记录。

timestamp 和 watermark 的生成器可以分为两类

建议生成的工作越靠近 DataSource 越好。这样会方便让程序逻辑里面更多的 operator 去判断某些数据是否乱序。Flink 内部提供了很好的机制去保证这些 timestamp 和 watermark 被正确地传递到下游的节点。

Watermark 传播

具体的传播策略基本上遵循这三点。

  1. watermark 会以广播的形式在算子之间进行传播。比如说上游的算子,它连接了三个下游的任务,它会把自己当前的收到的 watermark 以广播的形式传到下游。

  2. 如果在程序里面收到了一个 Long.MAX_VALUE 这个数值的 watermark,就表示对应的那一条流的一个部分不会再有数据发过来了它相当于就是一个终止的一个标志

  3. 对于单流而言,这个策略比较好理解,而对于有多个输入的算子,watermark 的计算就有讲究了,一个原则是:单输入取其大,多输入取小

然后在计算 watermark 的时候,对于单个输入而言是取他们的最大值,因为我们都知道 watermark 应该遵循一个单调递增的一个原则。对于多输入,它要统计整个算子任务的 watermark 时,就会取这三个计算出来的 watermark 的最小值。即一个多个输入的任务,它的 watermark 受制于最慢的那条输入流。这一点类似于木桶效应,整个木桶中装的水会就是受制于最矮的那块板

watermark 在传播的时候有一个特点是,它的传播是幂等的。多次收到相同的 watermark,甚至收到之前的 watermark 都不会对最后的数值产生影响,因为对于单个输入永远是取最大的,而对于整个任务永远是取一个最小的。

同时我们可以注意到这种设计其实有一个局限,具体体现在它没有区分你这个输入是一条流多个 partition 还是来自于不同的逻辑上的流的 JOIN。对于同一个流的不同 partition,我们对他做这种强制的时钟同步是没有问题的,因为一开始就是把一条流拆散成不同的部分,但每一个部分之间共享相同的时钟。但是如果算子的任务是在做类似于 JOIN 操作,那么要求你两个输入的时钟强制同步其实没有什么道理的,因为完全有可能是把一条离现在时间很近的数据流和一个离当前时间很远的数据流进行 JOIN,这个时候对于快的那条流,因为它要等慢的那条流,所以说它可能就要在状态中去缓存非常多的数据,这对于整个集群来说是一个很大的性能开销

ProcessFunction

在正式介绍 watermark 的处理之前,先简单介绍 ProcessFunction,因为 watermark 在任务里的处理逻辑分为内部逻辑和外部逻辑。外部逻辑其实就是通过ProcessFunction来体现的,如果你需要使用 Flink 提供的时间相关的 API 的话就只能写在 ProcessFunction 里

ProcessFunction 和时间相关的功能主要有三点:

一个简单的应用是,我们在做一些时间相关的处理的时候,可能需要缓存一部分数据,但这些数据不能一直去缓存下去,所以需要有一些过期的机制,我们可以通过 timer 去设定这么一个时间,指定某一些数据可能在将来的某一个时间点过期,从而把它从状态里删除掉。所有的这些和时间相关的逻辑在 Flink 内部都是由自己的 Time Service(时间服务)完成的。

Watermark 处理

时间和Watermark的本质

干涉Watermark的传播

在operator级别做代码的编写,function函数级别是不行的

参考自
https://ververica.cn/developers/advanced-tutorial-2-time-depth-analysis/
https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/event_timestamps_watermarks.html
https://www.jianshu.com/p/8c4a1861e49f

上一篇下一篇

猜你喜欢

热点阅读