Flink 學習 — Flink 中幾種 Time 詳解


前言

Flink 在流程序中支持不同的 Time 概念,就比如有 Processing Time、Event Time 和 Ingestion Time。

下面我們一起來看看這幾個 Time:

Processing Time

Processing Time 是指事件被處理時機器的系統時間。

當流程序在 Processing Time 上運行時,所有基於時間的操作(如時間窗口)將使用當時機器的系統時間。每小時 Processing Time 窗口將包括在系統時鍾指示整個小時之間到達特定操作的所有事件。

例如,如果應用程序在上午 9:15 開始運行,則第一個每小時 Processing Time 窗口將包括在上午 9:15 到上午 10:00 之間處理的事件,下一個窗口將包括在上午 10:00 到 11:00 之間處理的事件。

Processing Time 是最簡單的 “Time” 概念,不需要流和機器之間的協調,它提供了最好的性能和最低的延遲。但是,在分布式和異步的環境下,Processing Time 不能提供確定性,因為它容易受到事件到達系統的速度(例如從消息隊列)、事件在系統內操作流動的速度以及中斷的影響。

Event Time

Event Time 是事件發生的時間,一般就是數據本身攜帶的時間。這個時間通常是在事件到達 Flink 之前就確定的,並且可以從每個事件中獲取到事件時間戳。在 Event Time 中,時間取決於數據,而跟其他沒什么關系。Event Time 程序必須指定如何生成 Event Time 水印,這是表示 Event Time 進度的機制。

完美的說,無論事件什么時候到達或者其怎么排序,最后處理 Event Time 將產生完全一致和確定的結果。但是,除非事件按照已知順序(按照事件的時間)到達,否則處理 Event Time 時將會因為要等待一些無序事件而產生一些延遲。由於只能等待一段有限的時間,因此就難以保證處理 Event Time 將產生完全一致和確定的結果。

假設所有數據都已到達, Event Time 操作將按照預期運行,即使在處理無序事件、延遲事件、重新處理歷史數據時也會產生正確且一致的結果。 例如,每小時事件時間窗口將包含帶有落入該小時的事件時間戳的所有記錄,無論它們到達的順序如何。

請注意,有時當 Event Time 程序實時處理實時數據時,它們將使用一些 Processing Time 操作,以確保它們及時進行。

Ingestion Time

Ingestion Time 是事件進入 Flink 的時間。 在源操作處,每個事件將源的當前時間作為時間戳,並且基於時間的操作(如時間窗口)會利用這個時間戳。

Ingestion Time 在概念上位於 Event Time 和 Processing Time 之間。 與 Processing Time 相比,它稍微貴一些,但結果更可預測。因為 Ingestion Time 使用穩定的時間戳(在源處分配一次),所以對事件的不同窗口操作將引用相同的時間戳,而在 Processing Time 中,每個窗口操作符可以將事件分配給不同的窗口(基於機器系統時間和到達延遲)。

與 Event Time 相比,Ingestion Time 程序無法處理任何無序事件或延遲數據,但程序不必指定如何生成水印。

在 Flink 中,,Ingestion Time 與 Event Time 非常相似,但 Ingestion Time 具有自動分配時間戳和自動生成水印功能。

說了這么多概念比較干澀,下面直接看圖:

設定時間特性

Flink DataStream 程序的第一部分通常是設置基本時間特性。 該設置定義了數據流源的行為方式(例如:它們是否將分配時間戳),以及像 KeyedStream.timeWindow(Time.seconds(30)) 這樣的窗口操作應該使用上面哪種時間概念。

以下示例顯示了一個 Flink 程序,該程序在每小時時間窗口中聚合事件。

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);

// 其他
// env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
// env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

DataStream<MyEvent> stream = env.addSource(new FlinkKafkaConsumer09<MyEvent>(topic, schema, props));

stream
    .keyBy( (event) -> event.getUser() )
    .timeWindow(Time.hours(1))
    .reduce( (a, b) -> a.add(b) )
    .addSink(...);

Event Time 和 Watermarks

注意:Flink 實現了數據流模型中的許多技術。有關 Event Time 和 Watermarks 的詳細介紹,請查看以下文章:

支持 Event Time 的流處理器需要一種方法來衡量 Event Time 的進度。 例如,當 Event Time 超過一小時結束時,需要通知構建每小時窗口的窗口操作符,以便操作員可以關閉正在進行的窗口。

Event Time 可以獨立於 Processing Time 進行。 例如,在一個程序中,操作員的當前 Event Time 可能略微落后於 Processing Time (考慮到接收事件的延遲),而兩者都以相同的速度進行。另一方面,另一個流程序可能只需要幾秒鍾的時間就可以處理完 Kafka Topic 中數周的 Event Time 數據。

Flink 中用於衡量 Event Time 進度的機制是 Watermarks。 Watermarks 作為數據流的一部分流動並帶有時間戳 t。 Watermark(t)聲明 Event Time 已到達該流中的時間 t,這意味着流中不應再有具有時間戳 t’<= t 的元素(即時間戳大於或等於水印的事件)

下圖顯示了帶有(邏輯)時間戳和內聯水印的事件流。在本例中,事件是按順序排列的(相對於它們的時間戳),這意味着水印只是流中的周期性標記。

Watermark 對於無序流是至關重要的,如下所示,其中事件不按時間戳排序。通常,Watermark 是一種聲明,通過流中的該點,到達某個時間戳的所有事件都應該到達。一旦水印到達操作員,操作員就可以將其內部事件時間提前到水印的值。

平行流中的水印

水印是在源函數處生成的,或直接在源函數之后生成的。源函數的每個並行子任務通常獨立生成其水印。這些水印定義了特定並行源處的事件時間。

當水印通過流程序時,它們會提前到達操作人員處的事件時間。當一個操作符提前它的事件時間時,它為它的后續操作符在下游生成一個新的水印。

一些操作員消耗多個輸入流; 例如,一個 union,或者跟隨 keyBy(…)或 partition(…)函數的運算符。 這樣的操作員當前事件時間是其輸入流的事件時間的最小值。 由於其輸入流更新其事件時間,因此操作員也是如此。

下圖顯示了流經並行流的事件和水印的示例,以及跟蹤事件時間的運算符。

原文地址:http://www.54tianzhisheng.cn/2018/12/11/Flink-time/

.

其他


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM