时间概念类型

对于流式数据处理,最大的特点是数据上具有时间的属性特征,Flink根据实际产生的位置不同,将时间区分为三种时间概念,分别为事件生成时间(EventTime)、事件接入时间(Ingestion Time)和事件处理时间(Processing Time)。

  • 事件时间(EventTime)是创建事件的时间。通常用事件中的时间戳记来描述,例如由生产传感器或生产服务附加。Flink通过时间戳分配器访问事件时间戳。

  • 接收时间(Ingestion Time)是事件在源操作员进入Flink数据流的时间。

  • 处理时间(Processing Time)是每个执行基于时间的操作的操作员的本地时间。
    ![图片说明](https://uploadfiles.nowcoder.com/images/20191012/9094293_1570882797266_CC5F487F62CC483287C1E5DF1ADA13B8 "图片标题")

事件时间

事件时间是每个独立事件在产生它的设备上发生的时间,这个时间通常在事件进入Flink之前就已经嵌入到事件中,时间顺序取决于事件产生的地方,和下游数据处理系统的时间无关。事件数据具有不变的事件时间属性,该时间自事件元素产生就不会改变。通常情况下可以在Flink系统中指定事件时间属性或者设定时间提取器来提取事件时间。
所有进入Flink流式系统处理的事件,其时间都是在外部系统中差生,经过网络进入到Flink系统内处理,在理论的情况下,事件时间对应的时间戳一定会早于在Flink系统中处理的时间戳,但在实际情况中往往会出现数据记录乱序、延迟到达等问题。基于EventTime的时间概念,数据处理过程依赖于数据本身产生的时间,而不是Flink系统中Operator所在主机节点的系统时间,这样能够借助于事件产生时的时间信息来还原事件的先后关系。

接入时间

接入时间是事件进入Flink的时间。在Source Operator中,每个记录以时间戳的形式获取Source的当前时间。
接入时间概念上介于事件时间和处理时间之间。与处理时间相比,它稍微昂贵一些,但是提供了更可预测的结果。由于摄取时间使用稳定的时间戳(在源处分配一次),和后续数据处理Operator所在机器的时钟没有关系,从而不会因为某台机器时钟不同步或网络时延而导致计算结果不准确的问题。
在 Flink 中,,Ingestion Time 与 Event Time 非常相似,但 Ingestion Time 具有自动分配时间戳和自动生成水印功能。Watermarks。

处理时间

Processing Time 是指事件被处理时机器的系统时间。
当流程序在 Processing Time 上运行时,所有基于时间的操作(如时间窗口)将使用当时机器的系统时间。每小时 Processing Time 窗口将包括在系统时钟指示整个小时之间到达特定操作的所有事件。
例如,如果应用程序在上午 9:15 开始运行,则第一个每小时 Processing Time 窗口将包括在上午 9:15 到上午 10:00 之间处理的事件,下一个窗口将包括在上午 10:00 到 11:00 之间处理的事件。
Processing Time 是最简单的 “Time” 概念,不需要流和机器之间的协调,它提供了最好的性能和最低的延迟。但是,在分布式和异步的环境下,Processing Time 不能提供确定性,因为它容易受到事件到达系统的速度(例如从消息队列)、事件在系统内操作流动的速度以及中断的影响。

EventTime和Watermarks

通常情况下由于网络或者系统等外部因素影响下,事件数据往往不能及时传输至Flink系统中,导致系统的不稳定而造成数据乱序到达或者延迟到达等问题,因此,需要有一种机制能够控制数据处理的进度。
Flink中衡量事件时间进度的机制是Watermark。Watermark作为数据流的一部分流动,并带有时间戳t。Watermark流作为数据流的一部分,一个时间戳t。一个Watermark(t)宣称事件时间已达到时间t的流,这意味着该流没有更多的元素与时间戳T” <= T(即事件与Watermark时间戳旧的或相等)。

下图显示了带有(逻辑)时间戳的事件流,以及内联的Watermark。在这个例子中,事件是按顺序排列的(相对于它们的时间戳),这意味着Watermark只是流中的周期标记。
![图片说明](https://uploadfiles.nowcoder.com/images/20191012/9094293_1570886559027_7746D1574FEF6B29011C022D431E616F "图片标题")
Watermark对于乱序流至关重要,如下图所示,其中事件不是按其时间戳排序的。通常,Watermark是一种声明,即到流中的那个点,直到某个时间戳的所有事件都应该到达。一旦Watermark到达Operator,Operator就可以将其内部事件时钟提前到Watermark的值。
![图片说明](https://uploadfiles.nowcoder.com/images/20191012/9094293_1570886754406_E4F1A7D37E430D54B636B0FF5C667987 "图片标题")

并行数据流中的Watermarks

Watermark在Source Operator中生成,并且在每个Source Operator的子Task中都会独立生成Watermark。在Source Operator 的子任务中生成后就会更新该Task的Watermark,且会逐步更新下游算子中的Watermark水位线,随后一致保持在该并发之中,直到下一次Watermark的生成,并对前面的Watermark进行覆盖
![图片说明](https://uploadfiles.nowcoder.com/images/20191012/9094293_1570887409794_0CDCFB9939E17A8012DCBD2457B54193 "图片标题")

Late Elements

上面的 watermark 让我们能够应对乱序的数据,但是真实世界中我们没法得到一个完美的 watermark 数值 — 要么没法获取到,要么耗费太大,因此实际工作中我们会使用近似 watermark — 生成 watermark(t) 之后,还有较小的概率接受到时间戳 t 之前的数据,在 Flink 中将这些数据定义为 “late elements”