一、时间语义
个人理解,时间语义就是指对于时间的相关理解。
在spark Streaming中大多数是根据实时的时间来进行处理的,假如一个数据因为网络延迟迟到了,会将其分到其他窗口中,或者丢弃,会导致时间,或者计算不准确。
而flink中存在时间语义以及水位线等方式来校验,保证时间的准确性。
时间语义(同样也是代码中设置时间的参数):
- Event Time:事件创建的时间。意为按照数据传入是时间戳作为时间,如果不设置指定时间字段,则按照默认本地时间戳作为时间语义。
- Ingestion Time:按照数据进入flink的时间进行统计。
- Processing Time:执行操作算子的本地系统时间,与机器相关。
对于某些场景,我们更加关心的事件发生的时间:比如求出5年前某个网页的PV数据。
设置时间特性的方法:
例:
//设置时间特性为日志时间
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
二、水位线(WaterMark)
就相当于现实时间,可以作为参考线,类似物理中的参考系,以水位线的时间来判断该日志数据有没有因为网络波动或者其他延迟而晚到,默认水位线插入时间为200ms,可以设置延迟时间,可以与窗口函数结合使用。
水位线:当流的时间属性是事件时间的时候,现在时间行进到哪里了?水位线是多少,当前时间就是多少。
逻辑时钟。和真实世界的时间完全没有关系。
水位线的默认计算公式:
水位线 = 观察到的事件携带的最大时间戳 – 最大延迟时间 - 1毫秒
最大延迟时间由程序员自己设定:env.getConfig().setAutoWatermarkInterval(5);
水位线的特点:
- 水位线和获取的数据中带的时间戳有关。
- 水位线只会增大,不会减小。
- 水位线可以设置多长时间插入一次,默认时间是200ms。
- 水位线 = 观察到的事件携带的最大时间戳 – 最大延迟时间 - 1毫秒
- 最大延迟时间可以自己设定。
水位线的传递:
在输入分区
Flink将数据流拆分为多个分区,并通过单独的算子任务并行地处理每个分区。每个分区都是一个流,里面包含了带着时间戳的数据和watermark。一个算子与它前置或后续算子的连接方式有多种情况,所以它对应的任务可以从一个或多个“输入分区”接收数据和watermark,同时也可以将数据和watermark发送到一个或多个“输出分区”。接下来,我们将详细描述一个任务如何向多个输出任务发送watermark,以及如何通过接收到的watermark来驱动事件时间时钟前进。
任务为每个输入分区维护一个分区水位线(watermark)。当从一个分区接收到watermark时,它会比较新接收到的值和当前水位值,然后将相应的分区watermark更新为两者的最大值。然后,任务会比较所有分区watermark的大小,将其事件时钟更新为所有分区watermark的最小值。如果事件时间时钟前进了,任务就将处理所有被触发的定时器操作,并向所有连接的输出分区发送出相应的watermark,最终将新的事件时间广播给所有下游任务。
如下图所示: