Flink-Timely Stream Processing(二)

一、简介
        实时流处理是有状态流处理的一种扩展,时间在其中起一定的作用。在进行时间序列分析时,在基于特定时间段(通常称为windows)进行聚合时,或者在进行事件处理时(事件发生的时间很重要),都会出现这种情况。
在下面的小节中,我们将重点介绍使用Flink应用程序时应该考虑的一些主题。

二、时间的概念:事件时间和处理时间
        当在流媒体程序(例如定义窗口)中提到时间时,可以引用不同的时间概念:
        1、Processing time: 是指机器执行相应操作的系统时间。
                当流媒体程序在Processing time上运行时,所有基于时间的操作(如时间窗口)将使用运行各自操作符的机器的系统时钟。每小时的处理时间窗口将包括系统时钟指示整个小时的时间之间到达特定操作员的所有记录。例如,如果应用程序在9:15am开始运行,第一个每小时的处理时间窗口将包括在9:15am到10:00am之间处理的事件,下一个窗口将包括在10:00am到11:00am之间处理的事件,以此类推。

                Processing time是时间的最简单概念,不需要在流和机器之间进行协调。它提供了最好的性能和最低的延迟。然而,在分布式和异步环境Processing time不提供决定论,因为它是容易的速度记录到系统中(例如从消息队列),运营商之间流动的速度记录在系统内部,并中断(预定,或以其他方式)。

        2、Event time:事件时间是每个单独事件在其产生设备上发生的时间。这个时间通常在记录输入Flink之前嵌入到记录中,并且事件时间戳可以从每个记录中提取出来。在事件时间,时间的进展取决于数据,而不是墙上的时钟。Event time程序必须指定如何生成事件时间水印,这是一种信号事件时间进展的机制。这种水印机制将在下面的一节中进行描述。

                在完美的世界中,Event time处理将产生完全一致和确定性的结果,无论事件何时到达或它们的顺序如何。但是,除非已知事件按顺序(按时间戳)到达,否则在等待无序事件时,事件时间处理会导致一些延迟。由于只能等待有限的时间,这就限制了事件时间应用程序的确定性。

                假设所有数据都已到达,事件时间操作将按预期运行,即使在处理无序或延迟的事件,或者在重新处理历史数据时,也将产生正确和一致的结果。例如,每小时的事件时间窗口将包含包含该小时内的事件时间戳的所有记录,而不考虑它们到达的顺序或它们被处理的时间。

                请注意,有时当Event time程序实时处理实时数据时,它们将使用一些处理时间操作,以确保它们以及时的方式进行。

三、Event Time and Watermarks
        注意:Flink从数据流模型实现了许多技术。对于事件时间和水印有一个很好的介绍,请看下面的文章。

        Tyler Akidau的《流媒体101》
        数据流模型论文
                1、支持事件时间的流处理器需要一种方法来度量事件时间的进程。例如,构建每小时窗口的窗口操作符需要在事件时间超过一小时时得到通知,以便操作符可以关闭正在运行的窗口。
                2、事件时间可以独立于处理时间进行(由墙上的时钟测量)。例如,在一个程序中,操作人员的当前事件时间可能略微落后于处理时间(考虑到接收事件的延迟),而两者以相同的速度进行。另一方面,另一个流媒体程序通过快速转发一些已经缓冲在Kafka主题(或另一个消息队列)中的历史数据,可能只需要几秒钟的处理就可以完成数周的事件时间。
                3、在Flink中,度量事件时间进程的机制是水印。水印流作为数据流的一部分,一个时间戳t。一个水印(t)宣称事件时间已达到时间t的流,这意味着不应该有更多的元素从流时间戳t ' < = t(即事件与时间戳或等于水印)。
                4、下图显示了具有(逻辑)时间戳和水印的事件流。在本例中,事件是按顺序排列的(与它们的时间戳相关),这意味着水印只是流中的周期性标记。
                
        水印对于无序的流是至关重要的,如下所示,其中事件不是按照它们的时间戳排序的。一般来说,水印是这样一种声明:到流中的那个点时,直到某个时间戳的所有事件都应该已经到达。一旦水印到达操作符,该操作符可以将其内部事件时钟提前到水印的值。

                    
        注意,事件时间由从生成它们的事件或触发这些元素创建的水印中新创建的流元素(或多个元素)继承。

四、Watermarks in Parallel Streams
        1、水印是在源函数处或直接在源函数之后生成的。源函数的每个并行子任务通常独立地生成其水印。这些水印定义了特定并行源上的事件时间。
        2、当水印流经流媒体程序时,它们会提前到达的运营商的事件时间。每当一个操作符提升它的事件时间时,它就会为它的后续操作符在下游生成一个新的水印。
        3、有些运算符使用多个输入流,例如,在keyBy(…)或partition(…)函数后的联合或操作符。这样的操作符的当前事件时间是其输入流的事件时间的最小值。当它的输入流更新它们的事件时间时,操作符也更新它们的事件时间。
        4、下图显示了通过并行流流动的事件和水印的示例,以及跟踪事件时间的操作符

五、延迟
        1、某些元素可能会违反水印条件,这意味着即使在水印(t)发生之后,仍会出现更多时间戳为t ' <= t的元素。事实上,在许多现实世界的设置中,某些元素可以被任意延迟,这使得不可能指定某个事件时间戳中所有元素的发生时间。此外,即使延迟是有限制的,但将水印延迟太多往往是不可取的,因为这会在评估事件时间窗口时造成太大的延迟。
        2、由于这个原因,流程序可能会显式地期望一些后期元素。晚元素是在系统的事件时间时钟(由水印发出信号)已经超过晚元素的时间戳之后到达的元素。有关如何在事件时间窗口中处理延迟元素的详细信息,请参见允许延迟。        

六、窗口
        1、聚合事件(例如计数、总和)在流中的工作方式与在批处理中不同。例如,不可能计算流中的所有元素,因为流通常是无限的(无界的)。相反,流上的聚合(计数、总和等)是由窗口限定的,比如“过去5分钟的计数”,或者“过去100个元素的总和”。
        2、窗口可以是时间驱动的(例如:每30秒)或数据驱动的(例如:每100个元素)。一个典型的区分不同类型的窗口,例如滚动窗口(没有重叠)、滑动窗口(有重叠)和会话窗口(被不活动的间隙打断)。

     有关windows的其他示例,请查看这篇链接博客,或者查看DataStream API的窗口文档