一.概述
生成时间戳/水印与在事件时间有关。有关事件时间, 处理时间和摄取时间,参考:事件时间概述
为了处理事件时间,流式传输程序需要相应地设置时间特征。
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
二.分配时间戳
为了使用事件时间,Flink需要知道事件的时间戳,这意味着流中的每个元素都需要分配其事件时间戳。这通常是通过从元素的某个字段访问/提取时间戳来完成的。
时间戳分配与生成水印齐头并进,水印告诉系统事件时间的进展。
有两种分配时间戳和生成水印的方法:
- 直接在数据流源中生成。
- 通过时间戳分配器/水印生成器:在Flink中,时间戳分配器还定义要发送的水印。
注意:自1970年1月1日T00:00:00Z的Java时代以来,时间戳和水印都指定为毫秒。
三.带有时间戳和水印的源函数
流源可以将时间戳直接分配给它们产生的元素,并且它们还可以发出水印。完成此操作后,无需时间戳分配器。请注意,如果使用时间戳分配器,则源所提供的任何时间戳和水印都将被覆盖。
要将时间戳直接分配给源中的元素,源必须使用SourceContext上的collectWithTimestamp(…) 方法。要生成水印,源必须调用该emitWatermark(Watermark)函数。
下面是一个简单的示例(非检查点)源,该源分配时间戳并生成水印:
override def run(ctx: SourceContext[MyType]): Unit = {
while (/* condition */) {
val next: MyType = getNext()
ctx.collectWithTimestamp(next, next.eventTimestamp)
if (next.hasWatermarkTime) {
ctx.emitWatermark(new Watermark(next.getWatermarkTime))
}
}
}
四.时间戳分配器/水印生成器
时间戳分配器获取流并产生带有时间戳的元素和水印的新流。如果原始流已经具有时间戳或水印,则时间戳分配器将覆盖它们。
时间戳分配器通常在数据源之后立即指定,但并非严格要求这样做。例如,一种常见的模式是在时间