Flink的Time Extractor和Watermark Emitter

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxcaifly/article/details/84143028

前言

Flink提供了抽象类来让开发者赋值自己的时间戳并发送他们自己的Watermark。更具体来说,开发者需要依照不同用例情况来实现接口AssignerWithPeriodicWatermarks或接口AssignerWithPunctuatedWatermarks。简而言之,前一个接口将会周期性发送Watermark,而第二个接口根据一些到达数据的属性,例如一旦在流中碰到一个特殊的element便发送Watermark。下面有一个AssignerWithPunctuatedWatermarks的例子:

public class ConnectedCarAssigner implements AssignerWithPunctuatedWatermarks<ConnectedCarEvent> {
	@Override
	public long extractTimestamp(ConnectedCarEvent event, long previousElementTimestamp) {
		return event.timestamp;
	}

	@Override
	public Watermark checkAndGetNextWatermark(ConnectedCarEvent event, long extractedTimestamp) {
		// 每个事件都发射一个watermark
		return new Watermark(extractedTimestamp - 30000);
	}
}

为了进一步简化开发者开发类似的task,Flink自带了一些预先实现的timestamp assigner。本节提供了它们的一个列表。除过引用即用的函数,这些预先实现的assigner还可以作为自定义assigner的实现示例。

递增时间戳的Assigner

最简单的周期性Watermark生成的特例便是由一个给定的Source task所见的时间戳都以递增顺序发生的情况。在这种情况下,由于不会有比当前时间戳更早的时间戳到达,故总是可以将当前时间戳看作是一个Watermark。

注意上述情况仅在每个并行数据源task的时间戳都是以递增顺序到达时才是必要的,例如,在某特定部署中,一个Kafka分区是由一个并行性数据源读取的,那么上述情况仅在每个Kafka分区内的时间戳都是递增顺序出现时才是必要的。Flink的Watermark合并机制保证会在任何并行流在进行shuffle、 union、 connect或merge后都可以生成正确的Watermark。

DataStream<MyEvent> stream = ...
DataStream<MyEvent> withTimestampsAndWatermarks = 
  stream.assignTimestampsAndWatermarks(new AscendingTimestampExtractor<MyEvent>() {

  @Override
  public long extractAscendingTimestamp(MyEvent element) {
    return element.getCreationTime();
  }
});

允许固定量的迟到数据的Assigner

另一个周期性Watermark生成的例子是Watermark落在流中的一个固定时间段内观察到的最大(事件时间的)时间戳的后面。该情况同样包括预先知道在流中将会遇到的最大迟到量(lateness)的情况,例如创建的一个测试用的自定义source中,它的element的时间戳会分布在一个固定的时间段内。Flink为这种情况提供了BoundedOutofOrdernessTimestampExtractor接口,该接口需要参数maxOutofOrderness,即在一个element被给定窗口在计算最终结果时忽略之前(即该element过期前),所允许该element迟到的最大lateness。lateness的值为"t-t_w",其中t是一个element的(事件时间的)时间戳,t_w是前一个watermark。如果lateness > 0,则我们就认为该element已经迟到,并且在job计算对应窗口的结果时忽略它。

	public static class TaxiRideTSExtractor extends BoundedOutOfOrdernessTimestampExtractor<TaxiRide> {

		public TaxiRideTSExtractor() {
			super(Time.seconds(60));
		}

		@Override
		public long extractTimestamp(TaxiRide ride) {
			if (ride.isStart) {
				return ride.startTime.getMillis();
			}
			else {
				return ride.endTime.getMillis();
			}
		}
	}

猜你喜欢

转载自blog.csdn.net/hxcaifly/article/details/84143028
今日推荐