Flink數據流編程模型(Dataflow Programming Model)

目錄

抽象層次(Levels of Abstraction)

程序與數據流(Programs and Dataflows)

Parallel Dataflows(並行數據流)

窗口(Windows)

時間(Time)

有狀態操作(Stateful Operations)

容錯檢查點(Checkpoints for Fault Tolerance)

流中的批(Batch on Streaming)


原文鏈接

抽象層次(Levels of Abstraction)

        Flink提供了不同層次的抽象來開發流/批處理(streaming/batch)應用程序。如下:

抽象級別從低到高依次是:Stateful Stream Processing —> DataStream/DataSet API —> Table API —> SQL。

(1)Stateful Stream Processing

        它是整個抽象的最底層,通過過程函數(Process Function)嵌入到DataStream API中。它允許用戶自由地處理來自一個或多個流(streams)的事件(events),並使用一致的容錯狀態(consistent fault tolerant state)。此外,用戶可以註冊事件時間和處理時間回調,讓程序實現複雜的計算。

(2)DataStream/DataSet API

        實際上,大多數應用程序不需要上面描述的低級抽象(指的是Stateful Stream Processing),而是根據核心API進行編程,如DataStream API(有界/無界流,bounded/unbounded streams)和DataSet API(有界數據集,bounded data sets)。這些連貫api爲數據處理提供了常見的構建塊,比如用戶指定的各種形式的轉換(transformations)、連接(joins)、聚合(aggregations)、窗口(windows)、狀態(state)等。在這些api中處理的數據類型(Data types)在各自的編程語言中表示爲類。

        低層流程功能與DataStream API集成,使得僅對某些操作進行低層抽象成爲可能。DataSet API在有界數據集上提供了額外的原語(primitives ),比如循環/迭代。

(3)Table API

        它是一種以表爲中心的聲明式DSL,它可以動態更改表(在表示流時)。表API遵循(擴展的)關係模型:表附帶一個模式(類似於關係數據庫中的表),並且Table API提供了類似的操作,如選擇(select)、投射(project)、連接(join)、分組(group-by)、聚合(aggregate)等。表API程序以聲明的方式定義應該執行的邏輯操作,而不是確切地指定操作代碼的外觀。儘管表API可以通過各種類型的用戶定義函數進行擴展,但它的表達式較少

(4)SQL

        Flink提供的最高級抽象是SQL。這種抽象在語義和表達上與Table API相似,但是將程序表示爲SQL查詢表達式。SQL抽象與Table API密切交互,可以在Table API中定義的表上執行SQL查詢。

 

程序與數據流(Programs and Dataflows)

        Flink程序的基本構建塊是流(streams )和轉換(transformations)。從概念上講,流(streams )是數據記錄的流(flow)(可能是永無休止的),而轉換(transformations)是將一個或多個流作爲輸入,併產生一個或多個輸出流的操作。

        當執行時,Flink程序被映射爲流動的數據流(streaming dataflows),包括流和轉換操作符。每個數據流(dataflow)從一個或多個源(sources )開始,以一個或多個接收(sinks)結束。數據流(dataflow)類似於任意有向無環圖(DAGs)。儘管通過迭代構造允許特殊形式的環(cycles ),但爲了簡單起見,我們在大多數情況下將忽略這一點,也就是仍然看成有向無環圖(筆者注)。下面看個例子:

圖的上半部分是程序,主要包含了三個部分:source、transfomation和sink。圖的下半部分是程序對應的數據流(dataflow)。

筆者注:本文將DataStream和Dataflow都翻譯爲數據流, 從圖中能看出它倆的本質區別,DataStream是真實數據記錄的抽象,而Dataflow是程序對應的一個有向無環圖。如無特殊標註,數據流指的都是DataStream。

 

Parallel Dataflows(並行數據流)

        Flink中的程序本質上是並行(parallel )和分佈式的(distributed)。在程序執行期間,一個流(stream)有一個或多個流分區(stream partitions),每個操作(operator )有一個或多個操作子任務(operator subtasks)。操作子任務相互獨立,在不同的線程或者可能在不同的機器或容器上執行。

        一個操作的並行度(parallelism )指的是操作子任務的數量。流的並行度是產生該流的操作符的並行度。同一個程序的不同操作可能具有不同的並行度。如圖:

圖的上半部分是簡化的Dataflow,下半部分是從並行度角度分析的Dataflow。每個黃色實心圓表示一個操作子任務,灰色箭頭表示流。看到,在sink之前並行度都是2,sink的並行度是1。

        流可以以一對一模式(one-to-one pattern,也可以叫forwarding pattern)或重分佈模式(redistributing pattern)在兩個操作符之間傳輸數據。

(1)One-to-one streams

        比如圖中Source和map()之間的流就是一個One-to-one stream。它保持元素的分區(partitioning )和順序(ordering )。這意味着map()操作符的子任務[1](也就是圖中的map()[1])將看到與源操作符的子任務[1](也即是圖中的Source[1])同樣的元素,同樣的順序。

(2)Redistributing streams

        比如圖中的 map()keyBy/window之間的流是一個redistributing stream。它更改了流的分區。根據所選擇的轉換,每個操作子任務(比如map)將數據發送到不同的目標子任務(比如keyBy)。

原文中認爲keyBy/window和Sink之間也是一個Redistributing stream。但筆者認爲,它應該歸屬於One-to-one stream,理由是它也是one-to-one,並沒有發生Redistributing。

 

窗口(Windows)

        聚合事件(例如計數、總和)在流中的工作方式與在批處理中不同。例如,不可能計算(count)流中的所有元素,因爲流通常是無限的(無界的)。取而代之的是,流上的聚合是由窗口(windows)限定的,比如“最近5分鐘的計數”,或者“最近100個元素的總和”。

       窗口可以是時間驅動( time driven),例如每30秒統計一次,也可以是數據驅動的(data driven),比如每100個元素統計一次。窗口通常有如下三種,滾動窗口(tumbling windows)、滑動窗口(sliding windows)和會話窗口(session windows)。

(1)滾動窗口

圖中繪製了5個滾動窗口,每個窗口不重疊,無間隙。窗口大小相同。三個並行的用戶user1、user2和user3數據被唯一的劃分到某個窗口中參與計算。從示意圖來看,後一個窗口可以通過滾動前一個窗口來生成。

(2)滑動窗口

圖中繪製了4個滑動窗口,滑動窗口有窗口大小(window size)和窗口滑動(window slide)兩個要說構成。當window slide<window side,窗口之間存在重疊,部分數據會被重複計算,當window slide=window size,就是一個滾動窗口,當window slide>window size,窗口之間會存在空隙,部分數據計算會丟失。

(3)會話窗口

會話窗口沒有重疊,也沒有固定的開始和結束時間。會話窗口在一段時間內沒有接收到元素會關閉,這段時間對應圖中的session gap。如圖,對於user1,有4個會話窗口,注意到每個窗口中的數據個數不同,窗口的長度也不同,窗口之間的session gap也不同。

 

時間(Time)

        在一個流式程序中(比如定義上面的窗口)提及時間時,可以引用不同的時間概念(notions )。

(1)事件時間(Event Time)

        事件發生或者被創建的時間。它通常用事件中的時間戳(timestamp )來描述,例如,由生產傳感器或生產服務提供。

(2)攝入時間(Ingestion time)

        事件進入Flink Dataflow的源操作符(Operator source)的時間,也就是進入上面Parallel Dataflows一節中的Dataflow圖source的時間。可以簡單理解成爲進入Flink的時間。

(3)處理時間(Processing Time)

        事件被處理的時間。

按照時間順序,通常事件時間早於攝入時間,攝入時間早於處理時間。如圖:

圖中繪製了事件生產者(Event Producer),消息隊列(Message Queue)和Flink DataFlow。

 

有狀態操作(Stateful Operations)

        雖然數據流(dataflow )中的許多操作一次只查看單個事件(例如事件解析器),但有些操作記住跨多個事件的信息(例如窗口操作符)。這些操作稱爲有狀態操作。

        有狀態操作的狀態是在嵌入式鍵/值存儲中維護的。狀態是與有狀態操作符讀取的流一起嚴格分區和分發的。因此,只能在keyBy()函數之後的鍵流上訪問鍵/值狀態,並且僅限於與當前事件的鍵關聯的值。對齊流和狀態的鍵可以確保所有的狀態更新都是本地操作,從而保證沒有事務開銷的一致性。這種對齊還允許Flink透明地重新分配狀態和調整流分區。

 

容錯檢查點(Checkpoints for Fault Tolerance)

        Flink結合使用流重放(stream replay)和檢查點(checkpointing)來實現容錯。檢查點與每個輸入流中的特定點以及每個操作符的對應狀態相關。通過恢復操作符的狀態並從檢查點重播事件,流數據流可以從檢查點恢復,同時保持一致性(精確的一次處理語義)。檢查點間隔(checkpoint interval )是一種平衡執行期間容錯開銷和恢復時間(需要重放的事件數量)的方法。

 

流中的批(Batch on Streaming)

        Flink將批處理程序( batch programs)作爲流程序(streaming programs)的一種特殊情況來執行,這種流式有界的。因此,上面的概念以同樣的方式適用於批處理程序,也適用於流程序,但有一些小的例外:

(1)批處理程序的容錯不使用檢查點(checkpointing)。恢復是通過完全重放流來實現的。這是可能的,因爲輸入是有界的。這推動了更多的成本恢復,但使常規處理更便宜,因爲它避免了檢查點。

(2)DataSet API 中的狀態操作(Stateful operations )使用簡化的內存/核外數據結構,而不是鍵/值索引。

(3)DataSet API引入了特殊的同步(基於超步的)迭代,這隻能在有界流上實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章