Flink中window Trigger的理解

初识Flink,对于window相关的几个概念不甚了解,先抛出几个关键问题!

  • window是如何划分的?
  • watermark生成方式?多久产生一次?
  • window触发计算条件?
  • 延迟数据如何处理?

一、window是如何划分的?

window的划分与数据本身无关,而是由系统定义好的。

dataStreamSource.flatMap(new MyFlatMapFunction())
				.keyBy("")
				.timeWindow(Time.seconds(10))
                .allowedLateness(Time.seconds(12))	//允许多大的延迟

Time.seconds(10)表示10秒划分一个窗口,系统会这样划分窗口

[00:00:00,00:00:10)
[00:00:10,00:00:20)
...
[00:00:50,00:01:00)

当某个数据到达时,它属于哪个窗口就已经决定了。

二、watermark生成方式?多久产生一次?

1、生成watermark的方式有两种

  • Periodic :一定时间间隔或者达到一定的记录条数会产生一个watermark。
  • Punctuated:基于event time通过一定的逻辑产生watermark,比如收到一个数据就产生一个watermark。

2、watermark产生间隔

  • watermark生成的时间间隔(每n毫秒)是通过ExecutionConfig.setAutoWatermarkInterval()定义的,默认是0。
public class MyTimestampsAndWatermarks implements AssignerWithPeriodicWatermarks {
    private final long maxOutofOrderness = 5000;
    private long currentMaxTimestamp;
    
    @Override
    public long extractTimestamp(PacketDescriptor element, long previousElementTimestamp) {
        long timestamp = element.getTime();
        currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp);
        return timestamp;
    }
    
    @Override
    //每次调用分配器的getCurrentWatermark()方法时,如果返回的watermark非空且大于前一个watermark,则会发出新的watermark。
    public Watermark getCurrentWatermark() {
        return new Watermark(currentMaxTimestamp - maxOutofOrderness);
    }
}

三、window触发计算条件?

在Flink中,使用event-time模式时,默认提供的window有TumblingEventTimeWindows,SlidingEventTimeWindows,EventTimeSessionWindow等。在这三个默认提供的window operator中,都提供了默认的trigger,我们使用这三个方法时,没有写trigger,直接写window process,如 .reduce()。这是因为这三个window中的getDefaultTrigger()方法使用的是EventTimeTrigger,也就是它给我们提供了默认的trigger。

EventTimeTrigger.java

@Override
//每次数据进入该window时都会触发
public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
	if (window.maxTimestamp() <= ctx.getCurrentWatermark()) {
		// if the watermark is already past the window fire immediately
		return TriggerResult.FIRE;
	} else {
		ctx.registerEventTimeTimer(window.maxTimestamp());
		return TriggerResult.CONTINUE;
	}
}

@Override
//trigger注册的时间达到时触发
public TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) {
	return time == window.maxTimestamp() ?
		TriggerResult.FIRE :
		TriggerResult.CONTINUE;
}

@Override
public Trigger getDefaultTrigger(StreamExecutionEnvironment env) {
	return EventTimeTrigger.create();
}

window size = 10s
第一个数据(2019-06-03 17:00:02)到达时,此数据所属窗口为[2019-06-03 17:00:00,2019-06-03 17:00:10)

  • 调用MyTimestampsAndWatermarks的getCurrentWatermark()方法计算watermark为:2019-06-03 16:59:57

  • 调用onElement()方法,
    window.maxTimestamp() 为:2019-06-03 17:00:10
    ctx.getCurrentWatermark()为:2019-06-03 16:59:57
    if条件不满足,走else
    注册一个trigger,时间为:2019-06-03 17:00:10,,底层是一个set,同一个window相同时间的trigger,只会注册一个

第二个数据(2019-06-03 17:00:11)到达时,此数据所属窗口为[2019-06-03 17:00:10,2019-06-03 17:00:20)

  • 调用MyTimestampsAndWatermarks的getCurrentWatermark()方法计算watermark为:2019-06-03 17:00:06

  • 调用onElement()方法,上一个窗口
    window.maxTimestamp() 为:2019-06-03 17:00:10
    ctx.getCurrentWatermark()为:2019-06-03 17:00:06
    if条件不满足,走else
    注册一个trigger,时间为:2019-06-03 17:00:20

第三个数据(2019-06-03 17:00:15)到达时,此数据所属窗口为[2019-06-03 17:00:10,2019-06-03 17:00:20)

  • 调用MyTimestampsAndWatermarks的getCurrentWatermark()方法计算watermark为:2019-06-03 17:00:10

  • 调用onElement()方法,上一个窗口
    window.maxTimestamp() 为:2019-06-03 17:00:10
    ctx.getCurrentWatermark()为:2019-06-03 17:00:10
    满足if条件,触发小于等于此watermaker的trigger,window开始触发计算,触发后并清除此window的trigger注册的时间。

第四个数据(2019-06-03 17:00:05)到达时,假设此时watermark为:2019-06-03 17:00:30

  • 调用onElement()方法,上一个窗口
    window.maxTimestamp() 为:2019-06-03 17:00:10
    ctx.getCurrentWatermark()为:2019-06-03 17:00:30
    如果window.maxTimestamp() + allowedLateness > watermark,此窗口还未删除,直接触发窗口计算,并把当前数据跟之前此窗口计算的结果运算;如果window.maxTimestamp() + allowedLateness <= watermark,判断到此窗口已删除,则丢弃数据

window触发计算条件

  • watermark >= endTime
  • window里有元素
  • 触发window计算(trigger注册时间小于等于watermark的操作)

四、延迟数据如何处理?

WindowOperator.java 中processElement() 方法

for (W window: elementWindows) {
	 // drop if the window is already late
	 if (isWindowLate(window)) {
	     continue;
	 }
	 isSkippedElement = false;
	
	 windowState.setCurrentNamespace(window);
	 windowState.add(element.getValue());
	
	 triggerContext.key = key;
	 triggerContext.window = window;
	
	 TriggerResult triggerResult = triggerContext.onElement(element);
	
	 if (triggerResult.isFire()) {
	     ACC contents = windowState.get();
	     if (contents == null) {
	         continue;
	     }
	     emitWindowContents(window, contents);
	 }
	
	 if (triggerResult.isPurge()) {
	     windowState.clear();
	 }
	 registerCleanupTimer(window);
}

对于迟到太多的数据,其中 isWindowLate(window) 方法,也就是 window.maxTimestamp() + allowedLateness <= watermark ,若小于,则window过期,需要删除window对象,删除window状态;若大于,此窗口还未删除,直接触发窗口计算,并把当前数据跟之前此窗口计算的结果运算做merge操作。

参考:
https://www.jianshu.com/p/c8c789ff5570
https://blog.csdn.net/lmalds/article/details/52704170
https://www.jianshu.com/p/9db56f81fa2a

你可能感兴趣的:(大数据)