水印生成
水印生成的周期
默认的生成周期是200毫秒,我们可以在环境中修改这个时间
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
// TODO: 改变水印生成的周期
env.getConfig.setAutoWatermarkInterval(200L)
-
1
-
2
-
3
可以在这个类中找到代码 StreamExecutionEnvironment
我们可以看到ProcessingTime的生成水印的间隔是0
EventTime和IngestionTime默认生成水印间隔为200ms
public void setStreamTimeCharacteristic(TimeCharacteristic characteristic) {
this.timeCharacteristic = Preconditions.checkNotNull(characteristic);
if (characteristic == TimeCharacteristic.ProcessingTime) {
getConfig().setAutoWatermarkInterval(0);
} else {
getConfig().setAutoWatermarkInterval(200);
}
}
水印的生成的过程
- 有周期生成指定延迟的水印
- 针对每条数据判断条件当条件符合生成指定延迟的生成水印
AssignerWithPeriodicWatermarks生成水印方式的调用方式
1
- 2
- 3
从executionConfi中获取watermarkInterval ,大于0时会注册定时器,ProcessingTime 在未自定义水印生成间隔时,watermarkInterval 为0 所以不会创建水印,eventtime 时默认的水印生成间隔为200毫秒,即使未自定义水印的生成间隔 ,也会按照默认的时间间隔来生成水印。其实对于processtime 来说,生成水印是一种多余的操作,因为processtime 的都是有序的,不会存在跟对于process time的延迟数据。第一次生成水印是生成一个在now + watermarkInterval后会触发定时器,去生成水印,然后再创建定时器,然后就可以一直循环下去。
- 4
抽象类,我们看一下他的实现
SystemProcessingTimeService
会起一个TriggerTask线程放入timerService线程池中等待调度。
TriggerTask是一个内部类的run方法会回调TimestampsAndPeriodicWatermarksOperator的onProcessingTime方法
这里会先调udf(这里就是我们定义的AssignerWithPeriodicWatermarks生成水印方式)中的getCurrentWatermark获取水印,和当前水印时间判断是否需要发送新的水印,最后再次注册定时器
这样产生了一个循环,就会周期性生成水印了。
AssignerWithPunctuatedWatermarks生成水印方式的调用方式
直到这里可以看到处理流中每个元素的方法,先抽取时间戳,再执行是否生成水印的判断逻辑
这个逻辑 事件id=“sensor_1” 的事件才会生成水印 水印的延迟是1分钟
单并行度水印
整条流中只有一个水印
多并行的watermark
实际在多并行度执行时,WaterMark会有多个值存在,且是不会自动同步的。
watermark对齐会取所有channel最小的watermark。
假设流程设置并行度为2,两个source,同时调用WaterMark生成代码,不断根据处理元素的Event Time生成WaterMark,流程中会有两种不同步的WaterMark标志流。
如果此时有如下两个元素进入处理流程,并在代码中将WaterMark的timestamp打印出来的话,会是1536137355000和1536137349000两个不一样的WaterMark同时存在系统中。如果windows使用session windows, session gap 为3 seconds,理论上来说,Windows function应该被触发,但是,Windows并不会按照并行度为1时的设想调用apply处理方法,因为Windows总是以小的WaterMark为标准,windows同时收到两个并行source传过来的两个WaterMark标志,以1536137349000为标准,只认为1536137349000 WaterMark是有效的,1536137355000是无效的,因为只有一个并行处理的水印到达了1536137355000,另外一个并行度的水印还没到1536137355000。
分析:如果流程中存在两个 WaterMark时间:1536137349000和1536137355000,窗口endtime时间为1536137349000,窗口会被触发吗(默认的触发规则)?
答案是不一定会,在多并行度的情况下,Windows总是以小的WaterMark时间为标准,所以当前窗口认为时间为1536137349000,所以窗口函数,不会被触发。
那么何时会被触发呢?,当所有并行处理的1536137355000水印都到达之后,窗口函数才会被触发。