Flink教程(二)——事件時間

事件時間/處理時間/攝入時間java

        Flink支持流程序中的不一樣的時間通知。算法

        處理時間:處理時間是指執行操做的機器系統時間。異步

        當流程序運行在處理時間上時,全部的和時間相關的操做(好比時間窗口)都會使用運行各個操做運算的機器系統時鐘。舉個例子,一個小時單位的處理時間窗口會包含到達指定操做的全部記錄在系統時鐘是整個小時數之間。分佈式

        處理時間時最簡單的時間通知,它須要流和機器之間的協做。它提供了最好的算法表現和最低的延遲。然而在分佈式和異步環境中處理時間不提供可檢測機制,由於這樣會影響記錄到達系統的速度(好比從消息隊列中過來的),還有在系統中的算子之間的記錄流動速度。ide

        事件時間:事件時間是每一個發生在生產裝置中的獨立事件的時間。這個時間是在它們進入Flink和從記錄中抽取的事件時間戳以前就包含在記錄中的。一個小時單位的事件時間窗口包含拿到落地到那個小時內的事件時間戳,無論記錄什麼時候到達,無論他們的順序如何。函數

        儘管對於無序的事件,事件時間都會給出正確的結果,晚來的事件,或者蔥備份或者持久化的日誌中回放記錄。在事件時間中,依賴數據的處理時間,不是在任何現實時鐘時間。事件時間程序必須肯定怎樣產生事件時間水印。而這個就是事件時間的信號流程的機制。下面來描述這個機制:google

        事件時間流程老是發生在固定的延遲內,由於它自帶的等待遲到的事件和無序的事件一段時間的屬性。由於這個,事件時間程序常常和處理時間算子合併在一塊兒用。idea

        攝入時間:攝入時間是進入Flink的事件的時間。在源算子中每一個記錄都能將源的當前時間做爲一個時間戳,依賴於時間的操做就是這個時間戳。日誌

        攝入時間是位於事件時間和處理時間之間的概念。相比於處理時間,它的開銷更小,可是給予了更多預測結果。由於攝入時間使用了平衡時間戳(在源就分配了),對於記錄的不一樣的窗口操做都會產生相同的時間戳,然而在處理時間上,每一個窗口操做都會將記錄分配給不一樣的窗口(基於本地系統時鐘和任意傳輸時延)。code

        相比較於事件時間,攝入時間程序不一樣處理無序和遲到的事件,可是這個程序不必定義怎樣去生成水印。

        對於內部來講,攝入時間更像是事件時間,可是有自動的時間戳分配和自動的水印生成。

設置時間特徵

       Flink DataStream程序的第一步通常都是設置一個基本的時間特徵。這個設置定義了數據流源是怎麼樣執行的(好比說,他們分發了時間戳),還有窗口操做的時間通知的用法,像這樣:KeyedStream.timeWindow(Time.seconds(30))。

      下面的例子就展現了一個Flink程序是怎樣在一個時間單位的窗口中聚合事件的。窗口的行爲適配了時間特徵函數。

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);

// alternatively:
// 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(...);
val env = StreamExecutionEnvironment.getExecutionEnvironment

env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)

// alternatively:
// env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)
// env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

val stream: DataStream[MyEvent] = env.addSource(new FlinkKafkaConsumer09[MyEvent](topic, schema, props))

stream
    .keyBy( _.getUser )
    .timeWindow(Time.hours(1))
    .reduce( (a, b) => a.add(b) )
    .addSink(...)

      爲了在事件時間上運行這個例子,這個程序須要使用爲數據直接定義事件時間和水印的注入,或者程序必須在源以後注入一個時間戳發放者和水印生成器。這些函數描述了怎樣進入事件時間戳,還有亂序的事件流是怎樣體現的。

      下面的一段描述了在時間戳和水印背後的通用機制。做爲指導怎樣在Flink DataStream API中使用時間戳分發器和水印生成器。

事件時間和水印

      Flink從數據流模型中實現了許多技術。爲了作一個關於事件時間和水印的很好的介紹,咱們看下下面的文章:

Streaming 101 by Tyler Akidau

The Dataflow Model paper

      一個支持事件時間的流處理須要一種處理事件時間流程的措施。好比說,一個窗口操做間裏了時間的窗口須要經過當事件時間在一個小時的末了經過的時候,這樣這個操做就能夠在流程中關閉窗口。

      事件時間能夠獨立於處理時間進行。舉個例子,在一個程序中一個操做的當前事件時間牢牢落後於處理時間,這兩個時間幾乎是同樣的速度。從另外一個方面講,另外的流程序會花費僅僅幾秒的處理時間來處理持續數週的事件時間。經過已經存儲在一個kafka(或者其餘的消息隊列中間件) topic中的緩衝區域快進一些歷史數據。

      Flink處理事件時間的流程的機制就是水印。水印做爲數據流的一部分,獲取一個時間戳t。這個水印代表了事件時間在這個流中有一個到達時間t。代表在流中沒有一個帶時間戳的元素,他的時間戳t‘是小於t的。

      下面的圖展現了帶有邏輯時間戳的事件流,水印流轉其中。在這個例子中事件是排好序的,代表水印僅僅是在流中週期性的標記。

      水印對於無序的流來講相當重要,就像下面的圖中展現的同樣,事件不是按照時間戳排好序的。通常一個水印是經過流中的點來表示的,全部的在一個指定時間戳的事件都會到達。當一個水印到達一個操做時,那個操做就能夠將它的內部事件時間校準到和水印的值同樣。

並行流中的水印

      水印通常都是直接位於源函數以後的。每一個源函數的並行子任務都會產生獨立的水印。這些韓素音定義了在特定並行源上的事件時間。

      因爲水印是流轉在流程序中的,他們先於到達操做的事件時間。當一個操做先於事件時間時,他產生一個用於他的替代操做子的新水印下游。

      一些算子來自多個輸入流:一個聯結,舉個例子,做爲keyBy()或者partition()函數的參數的算子的事件事件時這個輸入流中最小的。輸入流和操做一塊兒更新他們的事件時間。

      下面的圖展現了一個在並行流中的事件和水印的例子,很明顯能看到跟隨事件時間的算子。

相關文章
相關標籤/搜索