简介
时态流处理是有状态流处理的扩展,其中时间在计算中起到一定的作用。当进行时间序列分析、基于一定时间段(通常称为窗口)进行聚合或进行事件处理时,就会涉及到时态流处理。
在接下来的章节中,我们将强调在使用时态Flink应用程序时应考虑的一些主题。
时间概念:事件时间&处理时间
当在流式程序中提到时间(例如定义窗口)时,可以引用不同的时间概念:
处理时间
处理时间指的是执行各自操作的机器的系统时间。 当流式程序以处理时间运行时,所有基于时间的操作(如时间窗口)将使用运行相应算子的机器的系统时钟。一个小时的处理时间窗口将包括在系统时钟指示整点之间到达特定算子的所有记录。例如,如果一个应用程序在上午9:15开始运行,第一个小时的处理时间窗口将包括在上午9:15到10:00之间处理的事件,下一个窗口将包括在上午10:00到11:00之间处理的事件,依此类推。 处理时间是最简单的时间概念,不需要流和机器之间的协调。它提供最佳性能和最低延迟。然而,在分布式和异步环境中,处理时间不能提供确定性,因为它容易受到记录进入系统的速度(例如从消息队列中)以及记录在系统内部的算子之间流动的速度和故障(计划的或其他原因)的影响。
事件时间
事件时间是每个单独事件在其生成设备上发生的时间。这个时间通常在记录进入Flink之前嵌入在记录中,并且可以从每个记录中提取事件时间戳。在事件时间中,时间的进度取决于数据,而不是任何墙上的时钟。事件时间程序必须指定如何生成事件时间水位线,这是在事件时间中表示进展的机制。
在完美的假设下,事件时间处理将产生完全一致和确定性的结果,不管事件何时到达或其排序如何。然而,除非已知事件按顺序(按时间戳)到达,否则事件时间处理会在等待无序事件时产生一些延迟。由于只能等待有限的时间,这限制了事件时间应用程序可以确定性的程度。
假设所有数据都已到达,事件时间操作将按预期运行,并在处理无序或延迟事件,或重新处理历史数据时产生正确和一致的结果。例如,一个小时的事件时间窗口将包含所有事件时间戳位于该小时内的记录,不管它们到达的顺序或处理的时间。(有关更多信息,请参见关于延迟的部分。)
请注意,有时当事件时间程序实时处理实时数据时,它们将使用一些处理时间操作,以确保它们及时进行进展。
事件时间&水位线
支持事件时间的流处理器需要一种方法来衡量事件时间的进展。例如,构建每小时窗口的窗口算子需要在事件时间超过一个小时的结束时间时得到通知,以便算子可以关闭正在进行中的窗口。
事件时间可以独立于处理时间(由墙上的时钟测量)进行进展。例如,在一个程序中,算子的当前事件时间可能略落后于处理时间(考虑到接收事件的延迟),而两者以相同的速度进行。另一方面,另一个流式程序可能在只有几秒处理时间的情况下,通过快速通过已缓冲在Kafka主题(或其他消息队列)中的一些历史数据前进几周的事件时间。
Flink中用于测量事件时间进展的机制是水位线。水位线作为数据流的一部分流动,并携带一个时间戳t。Watermark(t)声明事件时间已经到达了流中的时间t,这意味着流中不应该再有时间戳t’ <= t的元素(即时间戳早于或等于水位线的事件)。
下图显示了一个带有(逻辑)时间戳的事件流,并且水位线以内联方式流动。在这个例子中,事件是有序的(根据它们的时间戳),这意味着水位线只是流中的周期性标记。
水位线在无序流中至关重要,如下图所示,其中事件按照它们的时间戳没有排序。通常,水位线是流中到达某一点时的声明,该点之前的所有事件应该已经到达了某个时间戳。一旦水位线到达算子,算子可以将其内部事件时间时钟推进到水位线的值。
注意,事件时间是从生成它们的事件或触发创建这些元素的水位线中的新创建的流元素(或多个元素)继承的。
并行流中的水位线
水位线在源函数生成时或直接生成后生成。源函数的每个并行子任务通常独立生成其水位线。这些水位线定义了该特定并行源的事件时间。
随着水位线在流式程序中流动,它们推进到它们到达的算子的事件时间。每当算子推进其事件时间时,它会为下游的后续算子生成新的水位线。
一些算子会消费多个输入流,例如union算子或keyBy(...)
或partition(...)
方法后面的算子。这样一个算子的当前事件时间是其输入流事件时间的最小值。随着输入流更新其事件时间,算子也会更新其事件时间。
下图显示了事件和水位线通过并行流流动,并且算子跟踪事件时间的示例。
较小的水位线表示在该流中已经没有更早的事件了,而较大的水位线可能还有一些晚到的事件未到达。通过以较小的水位线对齐,可以确保所有相关事件都已经到达,避免错误的计算或处理。这种对齐策略可以保证流处理系统能够正确处理事件时间,并保证窗口的正确性和准确性。
迟到
有些元素可能会违反水位线条件,这意味着即使发生了Watermark(t),仍会出现更多具有时间戳t’ <= t的元素。实际上,在许多实际环境中,某些元素可能会任意延迟,这使得不可能指定某个事件时间戳的所有元素将发生的时间。此外,即使可以限制迟到的元素,过多延迟水位线通常也是不可取的,因为它会导致事件时间窗口的评估过程中出现过多的延迟。
因此,流式程序可能会明确地预期一些迟到的元素。迟到的元素是在系统的事件时间时钟(由水位线表示)已经超过迟到元素的时间戳的时间后到达的元素。有关如何在事件时间窗口中处理迟到元素的更多信息,请参见允许的延迟。
窗口
在流处理中,对事件进行聚合(例如计数、求和)与批处理中的方式有所不同。例如,不可能对流中的所有元素进行计数,因为流通常是无限的(无界的)。相反,在流上的聚合(计数、求和等)是通过窗口来进行范围限定的,例如”过去5分钟内的计数”或”最近100个元素的求和”。
窗口可以基于时间驱动(例如每30秒)或基于数据驱动(例如每100个元素)。通常可以区分不同类型的窗口,例如滚动窗口(无重叠)、滑动窗口(有重叠)和会话窗口(由不活动的间隙标记)