本文翻译自flink官网:https://ci.apache.org/projects/flink/flink-docs-release-1.7/dev/event_timestamps_watermarks.html

  • Assigning Timestamps

    • Source Functions with Timestamps and Watermarks

    • Timestamp Assigners / Watermark Generators

  • Timestamps per Kafka Partition

本章对应执行在事件时间的程序。事件事件、处理时间、摄取时间(收到数据的时间)的介绍可以跳转到 introduction to event time 。

要处理事件时间,流程序需要相应地设置时间特性。

val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

Assigning Timestamps

为了处理事件时间,Flink需要知道事件的时间戳,这意味着流中的每个元素都需要分配其事件时间戳。这通常通过从元素中的某个字段访问/提取时间戳来完成。

为了处理事件时间,Flink需要知道事件的时间戳,这意味着流中的每个元素都需要指定其事件时间戳(用事件的时间戳来指定)。这通常通过从元素中的某个字段访问/提取时间戳来完成。

时间戳分配与生成水印密切相关,水印告诉系统事件时间的进展。

有两种方法可以分配时间戳并生成水印:

  1. 直接在数据流源中

  2. 通过时间戳分配器/水印生成器:在Flink中,时间戳分配器还定义要发出的水印

注意:两周时间戳和水印都指定为毫秒,并且自Java纪元  1970-01-01 00:00:00 开始

Source Functions with Timestamps and Watermarks

stream source 可以直接为它们生成的元素分配时间戳,它们也可以发出水印。完成此操作后,不需要时间戳分配器。请注意,如果使用时间戳分配器,则将覆盖source提供的任何时间戳和水印。

要直接为source中的元素分配时间戳,source必须在SourceContext上使用collectWithTimestamp(...)方法。要生成水印,source必须调用emitWatermark(水印)功能。

下面是一个简单的(没有checkpoint)源代码示例,用于分配时间戳并生成水印:

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))
}
}
}

Timestamp Assigners / Watermark Generators

时间戳分配器获取流并生成带有带时间戳元素和水印的新流。如果原始流已经有时间戳和/或水印,则时间戳分配器会覆盖它们。

时间戳分配器通常在数据源之后立即指定,但并非严格要求这样做。例如,常见的模式是在时间戳分配器之前解析(MapFunction)和过滤(FilterFunction)。在任何情况下,需要在事件时间的第一个操作之前指定时间戳分配器(例如第一个窗口操作)。作为一种特殊情况,当使用Kafka作为流式传输作业的source时,Flink允许在source(或消费者)内指定时间戳分配器/水印发射器。有关如何执行此操作的更多信息,请参阅Kafka Connector文档。

注意:本节的其余部分介绍了程序员必须实现的主要接口,以便创建自己的时间戳提取器/水印发射器。要查看Flink附带的预先实现的提取器,请参阅预定义的时间戳提取器/水印发射器页面。

val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) val stream: DataStream[MyEvent] = env.readFile(
myFormat, myFilePath, FileProcessingMode.PROCESS_CONTINUOUSLY, 100,
FilePathFilter.createDefaultFilter()) val withTimestampsAndWatermarks: DataStream[MyEvent] = stream
.filter( _.severity == WARNING )
.assignTimestampsAndWatermarks(new MyTimestampsAndWatermarks()) withTimestampsAndWatermarks
.keyBy( _.getGroup )
.timeWindow(Time.seconds(10))
.reduce( (a, b) => a.add(b) )
.addSink(...)

With Periodic Watermarks

AssignerWithPeriodicWatermarks定期分配时间戳并生成水印(可能取决于流元素,或纯粹基于处理时间)。

生成水印的间隔(每n毫秒)由ExecutionConfig.setAutoWatermarkInterval(...)定义。每次调用分配器的getCurrentWatermark()方法,如果返回的水印非空且大于前一个水印,则会发出新的水印。

这里我们展示了两个使用周期性水印生成的时间戳分配器的简单示例。请注意,Flink附带了一个BoundedOutOfOrdernessTimestampExtractor,类似于下面显示的BoundedOutOfOrdernessGenerator,您可以在这里阅读。

/**
* This generator generates watermarks assuming that elements arrive out of order,
* but only to a certain degree. The latest elements for a certain timestamp t will arrive
* at most n milliseconds after the earliest elements for timestamp t.
*/
class BoundedOutOfOrdernessGenerator extends AssignerWithPeriodicWatermarks[MyEvent] { val maxOutOfOrderness = 3500L // 3.5 seconds var currentMaxTimestamp: Long = _ override def extractTimestamp(element: MyEvent, previousElementTimestamp: Long): Long = {
val timestamp = element.getCreationTime()
currentMaxTimestamp = max(timestamp, currentMaxTimestamp)
timestamp
} override def getCurrentWatermark(): Watermark = {
// return the watermark as current highest timestamp minus the out-of-orderness bound
new Watermark(currentMaxTimestamp - maxOutOfOrderness)
}
} /**
* This generator generates watermarks that are lagging behind processing time by a fixed amount.
* It assumes that elements arrive in Flink after a bounded delay.
*/
class TimeLagWatermarkGenerator extends AssignerWithPeriodicWatermarks[MyEvent] { val maxTimeLag = 5000L // 5 seconds override def extractTimestamp(element: MyEvent, previousElementTimestamp: Long): Long = {
element.getCreationTime
} override def getCurrentWatermark(): Watermark = {
// return the watermark as current time minus the maximum time lag
new Watermark(System.currentTimeMillis() - maxTimeLag)
}
}

With Punctuated Watermarks

要每个时间都可能生成新水印时生成水印(To generate watermarks whenever a certain event indicates that a new watermark might be generated,注:只会生成大于上一次水印的新水印),请使用AssignerWithPunctuatedWatermarks。对于此类,Flink将首先调用extractTimestamp(...)方法为元素分配时间戳,然后立即调用该元素上的checkAndGetNextWatermark(...)方法。

checkAndGetNextWatermark(...)方法传递在extractTimestamp(...)方法中分配的时间戳,并可以决定是否要生成水印。每当checkAndGetNextWatermark(...)方法返回非空水印,并且该水印大于最新的先前水印时,将发出该新水印。

class PunctuatedAssigner extends AssignerWithPunctuatedWatermarks[MyEvent] {

  override def extractTimestamp(element: MyEvent, previousElementTimestamp: Long): Long = {
element.getCreationTime
} override def checkAndGetNextWatermark(lastElement: MyEvent, extractedTimestamp: Long): Watermark = {
if (lastElement.hasWatermarkMarker()) new Watermark(extractedTimestamp) else null
}
}

注意:可以在每个事件上生成水印。然而,因为每个水印在下游引起一些计算,所以过多的水印会降低性能。

Timestamps per Kafka Partition

当使用Apache Kafka作为数据源时,每个Kafka分区可能具有简单的事件时间模式(升序时间戳或有界无序)。但是,当从Kafka消费流时,多个分区通常并行消耗,交错来自分区的事件并破坏每个分区模式(这是Kafka的消费者客户端工作的固有方式)。

在这种情况下,您可以使用Flink的Kafka分区感知水印生成。使用该功能,根据Kafka分区在Kafka消费者内部生成水印,并且每个分区水印的合并方式与在流shuffle上合并水印的方式相同。

例如,如果事件时间戳严格按每个Kafka分区升序,则使用升序时间戳水印生成器生成每分区水印将产生完美的整体水印。

下图显示了如何使用per-Kafka分区水印生成,以及在这种情况下水印如何通过流数据流传播。

val kafkaSource = new FlinkKafkaConsumer09[MyType]("myTopic", schema, props)
kafkaSource.assignTimestampsAndWatermarks(new AscendingTimestampExtractor[MyType] {
def extractAscendingTimestamp(element: MyType): Long = element.eventTimestamp
}) val stream: DataStream[MyType] = env.addSource(kafkaSource)

欢迎关注Flink菜鸟公众号,会不定期更新Flink(开发技术)相关的推文

【翻译】生成 Timestamps / Watermarks的更多相关文章

  1. Flink - Generating Timestamps / Watermarks

    https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/streaming/event_timestamps_watermar ...

  2. flink Window的Timestamps/Watermarks和allowedLateness的区别

    Watermartks是通过additional的时间戳来控制窗口激活的时间,allowedLateness来控制窗口的销毁时间.   注: 因为此特性包括官方文档在1.3-1.5版本均未做改变,所以 ...

  3. Flink学习(二)Flink中的时间

    摘自Apache Flink官网 最早的streaming 架构是storm的lambda架构 分为三个layer batch layer serving layer speed layer 一.在s ...

  4. Flink - watermark生成

    参考,Flink - Generating Timestamps / Watermarks watermark,只有在有window的情况下才用到,所以在window operator前加上assig ...

  5. Flink-v1.12官方网站翻译-P004-Flink Operations Playground

    Flink操作训练场 在各种环境中部署和操作Apache Flink的方法有很多.无论这种多样性如何,Flink集群的基本构件保持不变,类似的操作原则也适用. 在这个操场上,你将学习如何管理和运行Fl ...

  6. python爬虫调用谷歌翻译接口

    2019年7月4日15:53:17 (¦3[▓▓] 晚安 谷歌翻译环境 Python 3.6 第三方库 Execjs (pip install PyExecJS ) 文件列表 同目录下的四个文件: - ...

  7. Qt实现多国语言(即界面翻译)可实时进行切换

    .在工程文件添加 TRANSLATIONS = debug/lang_English.ts \ debug/lang_Chinese.ts .在需要翻译的地方用上tr 例如:setText(tr(&q ...

  8. Flink Program Guide (3) -- Event Time (DataStream API编程指导 -- For Java)

    Event Time 本文翻译自DataStream API Docs v1.2的Event Time ------------------------------------------------ ...

  9. [白话解析] Flink的Watermark机制

    [白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...

随机推荐

  1. java集合Map

    参考文章:https://blog.csdn.net/yjn1995/article/details/89784891 1.map接口 1.map接口实现类,HashMap.LinkListMap.H ...

  2. 为什么 MySQL 索引要使用 B+树而不是其它树形结构?比如 B 树?

    一个问题? InnoDB一棵B+树可以存放多少行数据?这个问题的简单回答是:约2千万 为什么是这么多呢? 因为这是可以算出来的,要搞清楚这个问题,我们先从InnoDB索引数据结构.数据组织方式说起. ...

  3. P1902 刺杀大使

    题目描述 伊朗伊斯兰革命卫队(某恐怖组织)正在策划一起刺杀行动,他们的目标是沙特驻美大 使朱拜尔.他们来到了沙特驻美使馆,准备完成此次刺杀,要进入使馆首先必须通过使馆前 的防御迷阵. 迷阵由 n*m ...

  4. python 之 字符串的常用方法

    split()函数: 返回以指定的字符将字符串分割成多个元素的列表 my_str = 'name is wangxiaoming' print(my_str.split()) #默认不写参数表示按空格 ...

  5. AtCoder Grand Contest 016题解

    传送门 \(A\) 直接枚举最终的字母然后模拟就行了-- 就这数据范围还是别学我写的这种做法了-- const int N=105; char s[N];int las[26],mx[26],n,re ...

  6. Tkinter 之TopLevel顶级窗口

    一.参数说明 width  设置宽度 height  设置高度 background(bg) 设置背景颜色默认值由系统指定为了防止更新,可以将颜色值设置为空字符串 borderwidth(bd) 设置 ...

  7. 【CSP模拟赛】避难向导(倍增lca&树的直径)

    耐力OIer,一天7篇博客 题目描述 “特大新闻,特大新闻!全国爆发了一种极其可怕的病毒,已经开始在各个城市 中传播开来!全国陷入了巨大的危机!大量居民陷入恐慌,想要逃到其它城市以 避难!经调查显示, ...

  8. shell脚本编程——生产实战案例

    生产实战案例     在日常的生产环境中,可能会遇到需要批量检查内网目前在线的主机IP地址有哪些,还可能需要检查这些在线的主机哪些端口是开放状态,因此依靠手工来检查是可以实现,但比较费时费力,所以需要 ...

  9. ES6中的class类的理解

    传统的javascript中只有对象,没有类的概念.它是基于原型的面向对象语言.原型对象特点就是将自身的属性共享给新对象.这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的感脚!非常容易让人 ...

  10. Mysql 查看所有线程,被锁的表等

    ## 查看所有MYSQl相关的线程 > show full processlist; ## 杀死线程id为2的线程 > kill 2 ## 查看服务器状态 > show status ...