含有时间的流处理是有状态流处理的扩展,其中时间在计算中起一定作用。 除其他外,当您进行时间序列分析、基于特定时间段(通常称为窗口)进行聚合时,或者在事件发生的时间很重要的情况下进行事件处理时,就会出现这种情况。
在以下部分中,我们将重点介绍在使用含有时间的 Flink 应用程序时应考虑的一些问题。
时间概念
事件时间与处理时间
在流式程序中引用时间时(例如定义窗口),可以引用不同的时间概念:
- 处理时间:处理时间是指执行相应操作的机器的系统时间。 当流程序在处理时间上运行时,所有基于时间的操作(如时间窗口)将使用运行相应操作符的机器的系统时钟。每小时处理时间窗口将包括在系统时钟指示整点时间之间到达特定操作员的所有记录。例如,如果应用程序在上午 9:15 开始运行,则第一个每小时处理时间窗口将包括在上午 9:15 和上午 10:00 之间处理的事件,下一个窗口将包括在上午 10:00 和上午 11:00 之间处理的事件,等等。 处理时间是最简单的时间概念,不需要流和机器之间的协调。它提供最佳性能和最低延迟。然而,在分布式和异步环境中,处理时间并不能提供确定性,因为它容易受到记录到达系统(例如从消息队列)的速度,以及记录在系统内操作员之间流动的速度以及中断(计划的或其他的)的影响。
- 事件时间:事件时间是每个单独事件在其生产设备上发生的时间。 这个时间通常在记录进入 Flink 之前嵌入到记录中,并且可以从每条记录中提取该事件时间戳。在事件时间中,时间的进展取决于数据,而不是任何挂钟。事件时间程序必须指定如何生成事件时间水印,这是在事件时间发出进度信号的机制。这种水印机制将在下面的后面部分中描述。 在一个完美的世界中,事件时间处理将产生完全一致和确定性的结果,无论事件何时到达或它们的顺序如何。但是,除非已知事件按顺序(按时间戳)到达,否则事件时间处理在等待无序事件时会产生一些延迟。由于只能等待一段有限的时间,这限制了事件时间应用程序的确定性。 假设所有数据都已到达,事件时间操作将按预期运行,并产生正确且一致的结果,即使在处理无序或延迟事件时,或者在重新处理历史数据时也是如此。例如,每小时的事件时间窗口将包含所有带有属于该小时的事件时间戳的记录,无论它们到达的顺序或处理时间。 (有关更多信息,请参阅有关迟到事件的部分。) 请注意,有时当事件时间程序实时处理实时数据时,它们会使用一些处理时间操作以保证它们及时进行。
事件时间与水印
注意:Flink 实现了数据流模型中的许多技术。 有关事件时间和水印的详细介绍,请查看以下文章。
- Streaming 101 by Tyler Akidau
- The Dataflow Model paper
支持事件时间的流处理器需要一种测量事件时间进度的方法。 例如,构建每小时窗口的窗口算子需要在事件时间超过一小时结束时得到通知,以便算子可以关闭正在进行的窗口。
事件时间可以独立于处理时间(由挂钟测量)进行。例如,在一个程序中,算子的当前事件时间可能稍微落后于处理时间(考虑到接收事件的延迟),而两者以相同的速度进行。另一方面,另一个流程序可能会通过几个星期的事件时间进行处理,只需几秒钟的处理,通过快速转发已经在 Kafka 主题(或另一个消息队列)中缓冲的一些历史数据。
Flink 中衡量事件时间进度的机制是水印。水印作为数据流的一部分流动并带有时间戳 t。 Watermark(t) 声明事件时间在该流中已达到时间 t,这意味着流中不应再有时间戳 t’ <= t 的元素(即时间戳早于或等于水印的事件)。
下图显示了带有(逻辑)时间戳的事件流,以及内联流动的水印。在此示例中,事件是有序的(相对于它们的时间戳),这意味着水印只是流中的周期性标记。
水印对于乱序流至关重要,如下图所示,其中事件不按时间戳排序。 一般来说,水印是一个声明,即到流中的那个点,直到某个时间戳的所有事件都应该已经到达。 一旦水印到达算子,算子可以将其内部事件时钟提前到水印的值。
请注意,事件时间由新创建的流元素(或多个元素)从生成它们的事件或触发创建这些元素的水印继承。
并行数据流中的水印
水印在源函数处或之后直接生成。 源函数的每个并行子任务通常独立生成其水印。 这些水印定义了特定并行源的事件时间。
当水印流经流程序时,它们会在它们到达的算子处提前事件时间。 每当算子提前其事件时间时,它就会为其后续算子在下游生成一个新的水印。
一些算子消耗多个输入流; 例如,联合,或 keyBy(…) 或 partition(…) 函数后面的运算符。 这样一个算子的当前事件时间是其输入流事件时间的最小值。 随着它的输入流更新它们的事件时间,算子也是如此。
下图显示了流经并行流的事件和水印示例,以及算子跟踪事件时间。
延迟
某些元素可能会违反水印条件,这意味着即使在 Watermark(t) 发生之后,还会出现更多时间戳 t’ <= t 的元素。 事实上,在许多现实世界的设置中,某些元素可以任意延迟,因此无法指定某个事件时间戳的所有元素将在何时发生。 此外,即使延迟可以有界,过多地延迟水印通常也是不可取的,因为它会导致事件时间窗口的评估延迟过多。
出于这个原因,流程序可能会明确地期望一些后期元素。 迟到的元素是在系统的事件时钟(由水印发出信号)已经超过迟到元素的时间戳之后到达的元素。 有关如何在事件时间窗口中使用迟到元素的更多信息,请参阅允许迟到。
窗口
聚合事件(例如,计数、总和)在流上的工作方式与批处理不同。 例如,不可能计算流中的所有元素,因为流通常是无限的(无界的)。 相反,流上的聚合(计数、总和等)由窗口限定,例如“过去 5 分钟的计数”或“最后 100 个元素的总和”。
Windows 可以是时间驱动的(例如:每 30 秒)或数据驱动的(例如:每 100 个元素)。 人们通常区分不同类型的窗口,例如滚动窗口(无重叠)、滑动窗口(有重叠)和会话窗口(由不活动间隙打断)。
请查看此博客文章以获取更多窗口示例或查看 DataStream API 的窗口文档。
翻译自:https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/concepts/time/
本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://cloud.tencent.com/developer/article/1940292