系列文章目录
目录
前言
Flink基于事件时间(EventTime)处理数据时需要指定水印(WaterMark)来标记数据处理到哪里,最近生产上把Flink版本从1.10升级到了1.12版本,发现WaterMark这里的api有些许不同,这里跟随着Flink1.12.0版本的官方文档记录下版本之间的不同支持吧。
参考官网:
https://ci.apache.org/projects/flink/flink-docs-release-1.12/zh/dev/event_timestamps_watermarks.html
一、新版本API区别
在Flink1.12版本中明确提到:
在 Flink 新的
WatermarkStrategy
,TimestampAssigner
和WatermarkGenerator
的抽象接口之前,Flink 使用的是AssignerWithPeriodicWatermarks
和AssignerWithPunctuatedWatermarks
。你仍可以在 API 中看到它们,但建议使用新接口,因为其对时间戳和 watermark 等重点的抽象和分离很清晰,并且还统一了周期性和标记形式的 watermark 生成方式。
二、WaterMark
1.watermark简介
为了使用事件时间语义,Flink 应用程序需要知道事件时间戳对应的字段,意味着数据流中的每个元素都需要拥有可分配的事件时间戳。其通常通过使用
TimestampAssigner
API 从元素中的某个字段去访问/提取时间戳。使用 Flink API 时需要设置一个同时包含
TimestampAssigner
和WatermarkGenerator
的WatermarkStrategy。
2.watermark使用
WatermarkStrategy
可以在 Flink 应用程序中的两处使用,第一种是直接在数据源上使用,第二种是直接在非数据源的操作之后使用,以Kafka数据源为例:
FlinkKafkaConsumer<MyType> kafkaSource = new FlinkKafkaConsumer<>("myTopic", schema, props);
kafkaSource.assignTimestampsAndWatermarks(
WatermarkStrategy.
.forBoundedOutOfOrderness(Duration.ofSeconds(20)));
DataStream<MyType> stream = env.addSource(kafkaSource);
在日常开发过程中我们往往使用watermark又分为周期性和标记性两种watermark。
3.内置watermark生成器
3.1.单调递增时间戳分配器
周期性 watermark 生成方式的一个最简单特例就是你给定的数据源中数据的时间戳升序出现。在这种情况下,当前时间戳就可以充当 watermark,因为后续到达数据的时间戳不会比当前的小。
注意:在 Flink 应用程序中,如果是并行数据源,则只要求并行数据源中的每个单分区数据源任务时间戳递增。例如,设置每一个并行数据源实例都只读取一个 Kafka 分区,则时间戳只需在每个 Kafka 分区内递增即可。Flink 的 watermark 合并机制会在并行数据流进行分发(shuffle)、联合(union)、连接(connect)或合并(merge)时生成正确的 watermark。
WatermarkStrategy.forMonotonousTimestamps();
注意:上面文档所说的 时间戳只要宝成在并行数据源中的每个分区是递增就行,记得在刚接触Flink时候,使用聚合操作时还会担心跨区间聚合会不会导致数据顺序错误的问题,这里文档已经明确指出,watermark合并机制会在并行数据做聚合等操作时生成正确的watermark,所以前面的问题无需担心。
3.2.固定延迟时间戳分配器
另一个周期性 watermark 生成的典型例子是,watermark 滞后于数据流中最大(事件时间)时间戳一个固定的时间量。该示例可以覆盖的场景是你预先知道数据流中的数据可能遇到的最大延迟,例如,在测试场景下创建了一个自定义数据源,并且这个数据源的产生的数据的时间戳在一个固定范围之内。Flink 针对上述场景提供了
boundedOutfordernessWatermarks
生成器,该生成器将maxOutOfOrderness
作为参数,该参数代表在计算给定窗口的结果时,允许元素被忽略计算之前延迟到达的最长时间。其中延迟时长就等于t_w - t
,其中t
代表元素的(事件时间)时间戳,t_w
代表前一个 watermark 对应的(事件时间)时间戳。如果lateness > 0
,则认为该元素迟到了,并且在计算相应窗口的结果时默认会被忽略。
WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(10))
总结
简单来说,如果大家使用过多个版本的Flink后会发现在之后迭代的版本中,flink把某些功能的接口封装的很好,已经无需在需要过多开发,watermark内置生成器已经能够满足大部分场景,而且比之前的版本更加方便,如果遇到不满足场景的业务,可以继承WatermarkGenerator接口实现自定义周期性水印和标记性水印。
欢迎大家扫一扫下面个人微信,我会拉大家进入大数据技术交流群,一起学习一起进步吧。