《從0到1學習Flink》—— Flink 中幾種 Time 詳解

前言

Flink 在流程序中支持不一樣的 Time 概念,就好比有 Processing Time、Event Time 和 Ingestion Time。git

下面咱們一塊兒來看看這幾個 Time:github

Processing Time

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

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

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

Processing Time 是最簡單的 「Time」 概念,不須要流和機器之間的協調,它提供了最好的性能和最低的延遲。可是,在分佈式和異步的環境下,Processing Time 不能提供肯定性,由於它容易受到事件到達系統的速度(例如從消息隊列)、事件在系統內操做流動的速度以及中斷的影響。函數

Event Time

Event Time 是事件發生的時間,通常就是數據自己攜帶的時間。這個時間一般是在事件到達 Flink 以前就肯定的,而且能夠從每一個事件中獲取到事件時間戳。在 Event Time 中,時間取決於數據,而跟其餘沒什麼關係。Event Time 程序必須指定如何生成 Event Time 水印,這是表示 Event Time 進度的機制。性能

完美的說,不管事件何時到達或者其怎麼排序,最後處理 Event Time 將產生徹底一致和肯定的結果。可是,除非事件按照已知順序(按照事件的時間)到達,不然處理 Event Time 時將會由於要等待一些無序事件而產生一些延遲。因爲只能等待一段有限的時間,所以就難以保證處理 Event Time 將產生徹底一致和肯定的結果。google

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

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

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 程序,該程序在每小時時間窗口中聚合事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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(…)函數的運算符。 這樣的操做員當前事件時間是其輸入流的事件時間的最小值。 因爲其輸入流更新其事件時間,所以操做員也是如此。

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

參考

https://github.com/zhisheng17/flink/blob/feature%2Fzhisheng_release_1.6/docs/dev/event_time.md

相關文章
相關標籤/搜索