1、时间语义
1.1、Event time(重点关注)
- 事件创建时间,时间值取决于 数据产生记录的事件;
- 只登记一次,并且EventTime也可以从记录中提取出来;
- 事件事件是每个单独事件在其进程上发生的事件,这个时间通常在记录进入Flink之前记录在对象中
1.2、Ingestion time
- IngestionTime是数据进入Apache Flink框架的时间,是在Source Operator中设置的
- 在源处只记录一次
1.3、Processing time
- 事件被Flink处理的时间,正在执行相应操作的机器的系统时间
- 提供了最佳性能和最低延迟
- 在分布式和异步环境中,处理事件存在延迟或者乱序问题
1.4、三种时间的比较
(1)EventTime
- 事件生成时的时间,在进入Flink之前就已经存在,可以从event的字段中抽取
- 必须指定watermarks的生成方式
- 优势:确定性:乱序、延时、或者数据重复等情况,都能给出正确的结果
- 弱点:处理无序事件时性能和延迟受到影响
- 应用场景:统计电商平台某宝在双十一在10min的成交额
(2)IngestTime
- 事件进入flink的时间,即在source里获取的当前系统的时间,后续操作统一使用该时间
- 不需要指定watermarks的生成方式(自动生成)
- 弱点:不能处理无序事件和延迟数据
- 应用场景:腾讯视频传递视频掉帧
(3)ProcessingTime - 执行操作的机器的当前系统时间(每个算子都不一样)
- 不需要流和机器之间的协调
- 优势:最佳的性能和最低的延迟
- 弱点:不确定性 ,容易受到各种因素影像(event产生的速度、到达flink的速度、在算子之间传输速度等),压根就不管顺序和延迟
(4)比较
- 性能: ProcessingTime> IngestTime> EventTime
- 延迟: ProcessingTime< IngestTime< EventTime
- 确定性: EventTime> IngestTime> ProcessingTime
1.5、时间语义设置
- 在环境中设置时间类型(1.13版本废弃)
// 1、环境配置
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
// 2、
- 不设置Time 类型,默认是processingTime
- 如果使用EventTime则需要在source之后明确指定Timestamp Assigner & Watermark Generator
2、WaterMark概述
2.1、有序&乱序数据
(1)有序流
- 一般都是用EventTime事件时间进行处理数据
[0,5)为一个桶:5来了之后,第一个桶计算完毕即将桶关闭,0进入第二个桶
(2)乱序流
- 更多场景(分布式环境,异步环境,网络波动),基于Event Time的数据流是无序的
[0,5)为一个桶:5来了之后,第一个桶计算完毕即将桶关闭,2,3延迟无法进入第二个桶,被丢弃
2.2、WaterMark 原理
(1)Timestamp
- 代表event time,实时系统中,由于各种原因造成的延时,造成某些消息发到flink的时间延时于事件产生的时间。如果 基于event time构建window,但是对于late element,我们又不能无限期的等下去,必须要有个机制来保证一个特定的时间后,必须触发window去进行计算了。这个特别的机制,就是watermark 。
(2)WaterMark
- 是event time处理进度的标志,仅限于event time下使用
- 表示比watermark更早(更迟)的事件已经到达(没有比水位线更低的数据)
- 基于watermark来进行窗口触发计算的判断
1、衡量数据是否乱序的时间,什么时候不用等早之前的数据
2、是一个全局时间戳,一个特殊字段,单调递增方式,主要和数据本身的时间戳作比较
3、计算方式:Watermaker = 当前计算窗口最大的事件事件 - 允许乱序延迟时间
(3)有序流Watermark
- 在某些情况下,基于Event Time的数据流是有续的
- 在有序流中,watermark就是一个简单的周期性标记。
(4)乱序流WaterMark
- 在更多场景下,基于Event Time的数据流是无续的
- 在无序流中,watermark至关重要,它告诉operator比watermark更早(更老/时间戳更小)的事件已经到达, operator可以将内部事件时间提前到watermark的时间戳(可以触发window计算啦)
W(20):告诉算子20之前的数据都到了,可以出发窗口计算
19:实际没到,数据不计入窗口,处理方式 - 单独存储丢弃数据可重算
24:被计入到20的窗口
(5)窗口触发计算时机
①Watermark之前:按照窗口的关闭时间点计算的
②Watermark之后:触发计算时机 - max(当前窗口事件时间)- 允许乱序延迟时间 >= Window Endtime窗口结束时间**
注意:出发计算后,其窗口数据再到达都会被丢弃,可另行存储处理
- 案例
windows大小为10s,窗口是W1[23:12:00~23:12:10],以下是数据的event time
数据A 23:12:07
数据B 23:12:11
数据C 23:12:08
数据D 23:12:17
数据E 23:12:09
Ⅰ、没加入watermark,由上到下进入flink
①数据B到了之后:W1就进行了窗口计算,数据只有A
②数据C迟到了3秒:到了之后,由于W1已经计算了,所以就丢失了数据C
Ⅱ、加入了watermark,允许5秒乱序延迟,由上到下进入flink
①数据A到达:watermark=12:07 - 5 = 12:02 < 12:10 ,所以不触发W1计算,A属于W1
②数据B到达:watermark = max{12:11, 12:07} - 5 =12:06 < 12:10,所以不触发W1计算**,B属于W2**
③数据C到达:watermark = max{12:08, 12:11, 12:07} - 5 = 12:06 <12:10,所以不触发W1计算,C属于W1
④数据D到达:watermark = max{12:17, 12:08, 12:11, 12:07} - 5 = 12:12 > 23:12:10,触发W1计算,D属于W2
⑤数据E到达:watermark=max{12:09,12:17,12:08,12:11,12:07} -5 =12:12 > 23:12:10,之前已经触发了W1计算,所以丢失了E数据
(6)watermark注意事项
- Watermark设置太小,影响数据准确性
- Watermark设置太大,影响数据实时性
2.3、并行流watemark
(1)多流watermark产生
在实际的流计算中往往一个job中会处理多个Source的数据,对Source的数据进行GroupBy分组,那么来自不同Source的相同key值会shuffle到同一个处理节点,并携带各自的Watermark,Apache Flink内部要保证Watermark要保持单调递增,多个Source的Watermark汇聚到一起时候可能不是单调自增的。
(2)多流的watermark的选择机制
- 通常情况下, watermark在source函数中生成,但是也可以在source后任何阶段,如果指定多次后面会覆盖前面的值。
- watermark通过operator时会推进operators处的当前event time,同时operators会为下游生成一个新的watermark。
- Apache Flink内部实现每一个边上只能有一个递增的Watermark, 当出现多流携带Eventtime汇聚到一起(Join or Union)时候,Apache Flink会选择所有流入的Eventtime中最小min(stream1, stream2…streamN)的一个向下游流出。从而保证watermark的单调递增和保证数据的完整性.
3、实战案例
未完待续