时间语义
事件时间(Event Time)
事件时间是数据生成的时间,是数据流中每个元素或者每个事件自带的时间属性,一般是事件发生的时间,在实际项目中作为前端的一个属性嵌入。在理想情况下,数据应当按照事件时间顺序到达集群节点,但是由于从产生一条数据到数据抵达集群有过多的中间步骤,一个较早发生的事件可能较晚到达,使用事件时间意味着会产生数据乱序。
处理时间(Processing Time)
处理时间执行处理操作的机器的系统时间,使用处理时间不需要依赖水位线,也无需缓存,实现也十分简单,是延迟最小的一种时间语义。
注入时间(Ingestion Time)
注入时间是数据进入 Source 算子的时间,任何一个算子的处理速度快慢可能影响到下游算子的处理时间,但是注入时间仅依赖于数据进入 Source 算子的时间,因此不会受制于不同算子的计算时间。
水位线和事件时间
水位线的物理意义有两点:
- 水位线本质是一个基于数据生成的、单调递增的时间戳;
- 水位线 W(t)表示当前数据流中的所有 t 时刻前的数据都已经到了。
水位线的传播
在实际计算过程中,Flink 的算子一般分布在多个并行的分区(或者称为实例)上,Flink 需要将 Watermark 在并行环境下向前传播。如下图所示,由于上游各分区的处理速度不同,到达当前算子的 Watermark 也会有先后快慢之分,每个算子子任务会维护来自上游不同分区的 Watermark 信息,这是一个列表,列表内对应上游算子各分区的 Watermark 时间戳等信息。每当一个上游传递过来一个水位线,实例会判断该水位线是否大于列表中记录的数值,如果大于则更新水位线。接着实例会遍历整个水位线列表找出最小值作为实例的事件时间,最后,实例会将更新的 Event Time 作为 Watermark 发送给下游所有算子子任务。
时间事件的提取和水位线的生成
周期性的生成水位线,默认周期是 200 毫秒 。可以使用 ExecutionConfig.setAutoWatermarkInterval()
方法进行设置。
我们也可以使用 assignTimestampsAndWatermarks()
来分配时间戳和水位线。该方法主要依赖于 WatermarkStrategy 接口,通过 WatermarkStrategy 我们可以为每个元素抽取时间戳并生成 Watermark。基本的使用方法如下:
DataStream.assignTimestampsAndWatermarks(WatermarkStrategy
.<Event>forBoundedOutOfOrderness(Duration.ZERO)
.withTimestampAssigner((SerializableTimestampAssigner<Event>)
(element, recordTimestamp) -> element.timeStamp))
forGenerator ()
方法用来生成 Watermark,本质是返回了一个 WatermarkGenerator 有俩种实现机制**,** BoundedOutOfOrdernessWatermarks(数据存在乱序的情况)
和 AscendingTimestampsWatermark(数据有序)
withTimestampAssigner ()
方法用来为数据流的每个元素设置时间戳
TTL
java
public void open(Configuration parameters) throws Exception {
// 创建MapState描述符
MapStateDescriptor<String, Long> descriptor = new MapStateDescriptor<>("myMapState", String.class, Long.class);
StateTtlConfig ttlConfig = StateTtlConfig
// 状态有效时间
.newBuilder(Time.seconds(10))
//设置状态更新类型
.setUpdateType(StateTtlConfig.UpdateType.OnReadAndWrite)
// 已过期但还未被清理掉的状态如何处理
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
// 过期对象的清理策略
.cleanupFullSnapshot()
.build();
descriptor.enableTimeToLive(ttlConfig);
mapState = getRuntimeContext().getMapState(descriptor);
}
配置分析
设置状态更新类型
setUpdateType(StateTtlConfig.UpdateType.OnReadAndWrite):
在读和写的时候更新过期时间
setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite):
只在创建和写的时候更新过期时间 (默认)
已过期但还未被清理掉的状态如何处理
setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
不返回过期值
setStateVisibility(StateTtlConfig.StateVisibility.ReturnExpiredIfNotCleanedUp)
可以返回过期值
过期转态的清理策略
⭐ lazy 删除策略:就是在访问 State 的时候根据时间戳判断是否过期,如果过期则主动删除 State 数据
⭐ full snapshot cleanup 删除策略:从状态恢复(checkpoint、savepoint)的时候采取做过期删除,但是不支持 rocksdb 增量 ck
⭐ incremental cleanup 删除策略:访问 state 的时候,主动去遍历一些 state 数据判断是否过期,如果过期则主动删除 State 数据
⭐ rocksdb compaction cleanup 删除策略:rockdb 做 compaction 的时候遍历进行删除。仅仅支持 rocksdb