Flink學習--Flink編程模型

目錄

Flink技術棧

編程模型

抽象級別

程序和數據流

並行數據流

窗口

時間

容錯檢查點

流上的批處理


Flink是一款分佈式的計算引擎,它可以用來做批處理,即處理靜態的數據集、歷史的數據集;也可以用來做流處理,即實時地處理一些實時數據流,實時地產生數據的結果;也可以用來做一些基於事件的應用。總而言之,Flink是一個Stateful Computations Over Streams,即數據流上的有狀態的計算。這裏面有兩個關鍵字,一個是Streams,Flink認爲有界數據集是無界數據流的一種特例,所以說有界數據集也是一種數據流,事件流也是一種數據流。Everything is streams,即Flink可以用來處理任何的數據,可以支持批處理、流處理、AI、MachineLearning等等。另外一個關鍵詞是Stateful,即有狀態計算。有狀態計算是最近幾年來越來越被用戶需求的一個功能。舉例說明狀態的含義,比如說一個網站一天內訪問UV數,那麼這個UV數便爲狀態。Flink提供了內置的對狀態的一致性的處理,即如果任務發生了Failover,其狀態不會丟失、不會被多算少算,同時提供了非常高的性能。

那Flink的受歡迎離不開它身上還有很多的標籤,其中包括性能優秀(尤其在流計算領域)、高可擴展性、支持容錯,是一種純內存式的一個計算引擎,做了內存管理方面的大量優化,另外也支持eventime的處理、支持超大狀態的Job、支持exactly-once的處理。

Flink技術棧

編程模型

抽象級別

  • 最底層級的抽象僅僅提供了有狀態流。它將通過過程函數(Process Function)被嵌入到DataStream API中。它允許用戶可以自由地處理來自一個或多個數據流的事件,並使用一致的容錯的狀態。除此之外,用戶可以註冊事件時間並處理時間回調,從而使程序可以處理複雜的計算。
  • 實際上,大多數應用並不需要上述的底層抽象,而是針對 核心API(Core APIs) 進行編程,比如DataStream API(有界或無界流數據)以及DataSet API(有界數據集)。這些API爲數據處理提供了通用的構建模塊,比如由用戶定義的多種形式的轉換(transformations),連接(joins),聚合(aggregations),窗口操作(windows),狀態(state)等等。這些API處理的數據類型以類(classes)的形式由各自的編程語言所表示。                                                                                               底層 過程函數(Process Function) 與 DataStream API 相集成,使其可以對某些特定的操作進行底層的抽象。DataSet API 爲有界數據集提供了額外的原語,例如循環與迭代。
  • Table API 是以  爲中心的聲明式DSL,其中表可能會動態變化(在表達流數據時)。Table API遵循(擴展的)關係模型:表有二維數據結構(schema)(類似於關係數據庫中的表),同時API提供可比較的操作,例如select、project、join、group-by、aggregate等。Table API程序聲明式地定義了 什麼邏輯操作應該執行 而不是準確地確定 這些操作代碼的看上去如何 。 儘管Table API可以通過多種類型的用戶自定義函數(UDF)進行擴展,其仍不如 核心API 更具表達能力,但是使用起來卻更加簡潔(代碼量更少)。除此之外,Table API程序在執行之前會經過內置優化器進行優化。                                 你可以在表與 DataStream/DataSet 之間無縫切換,以允許程序將 Table API 與 DataStream 以及 DataSet 混合使用。
  • Flink提供的最高層級的抽象是 SQL 。這一層抽象在語法與表達能力上與 Table API 類似,但是是以SQL查詢表達式的形式表現程序。SQL抽象與Table API交互密切,同時SQL查詢可以直接在Table API定義的表上執行。

程序和數據流

Flink程序的基礎構建模塊是 流(streams) 與 轉換(transformations)。(需要注意的是,Flink的DataSet API所使用的DataSets其內部也是流——更多內容將在之後討論。)概念上來講,是(可能永無止境的)數據記錄流,而 轉換 是一種操作,它取一個或多個流作爲輸入,並生產出一個或多個輸出流作爲結果。

執行時,Flink程序映射到 流數據流(streaming dataflows) ,由  以及轉換 算符 構成。每一個數據流起始於一個或多個 source,並終止於一個或多個 sink。數據流類似於任意的 有向無環圖 (DAG) 。雖然通過 迭代 構造允許特定形式的環,但是大多數情況下,簡單起見,我們都不考慮這一點。

A DataStream program, and its dataflow.

通常,程序中的轉換與數據流中的操作之間是一對一的關係。有時,然而,一個轉換可能由多個轉換操作構成。

並行數據流

Flink程序本質上是並行分佈的。在執行過程中,一個  包含一個或多個 流分區 ,而每一個 算符 包含一個或多個 算符子任務 。操作子任務間彼此獨立,以不同的線程執行,甚至有可能運行在不同的機器或容器上。

算符子任務的數量即這一特定算符的 並行度 。一個流的並行度即其生產算符的並行度。相同程序中的不同的算符可能有不同級別的並行度。

A parallel dataflow

流在兩個算符之間傳輸數據,可以通過 一對一 (或稱 forwarding )模式,或者通過 redistributing 模式:

  • 一對一 流(例如上圖中 Source 與 map() 算符之間)保持了元素的分區與排序。那意味着 map() 算符的子任務[1]將以與 Source 的子任務[1]生成順序相同的順序查看到相同的元素。
  • Redistributing 流(如上圖中 map() 與 keyBy/window 之間,以及 keyBy/window 與 Sink 之間)則改變了流的分區。每一個 算符子任務 根據所選擇的轉換,向不同的目標子任務發送數據。比如 keyBy() (根據key的哈希值重新分區), broadcast() ,或者 rebalance() (隨機重分區)。在一次 redistributing 交換中,元素間的排序只保留在每對發送與接受子任務中(比如, map() 的子任務[1]與 keyBy/window 的子任務[2])。因此在這個例子中,每個鍵的順序被保留下來,但是並行確實引入了對於不同鍵的聚合結果到達sink的順序的不確定性。

窗口

聚合事件(比如計數、求和)在流上的工作方式與批處理不同。比如,對流中的所有元素進行計數是不可能的,因爲通常流是無限的(無界的)。相反,流上的聚合需要由 窗口 來劃定範圍,比如 “計算過去的5分鐘” ,或者 “最後100個元素的和” 。

窗口可以是 事件驅動的 (比如:每30秒)或者 數據驅動的 (比如:每100個元素)。窗口通常被區分爲不同的類型,比如 滾動窗口 (沒有重疊), 滑動窗口 (有重疊),以及 會話窗口 (由不活動的間隙所打斷)

Time- and Count Windows

時間

當提到流程序(例如定義窗口)中的時間時,你可以參考不同的時間概念:

  • 事件時間(event time) 是事件創建的時間。它通常由事件中的時間戳描述,例如附接在生產傳感器,或者生產服務。Flink通過時間戳分配器訪問事件時間戳。
  • 攝入時間(ingestion time) 是事件進入Flink數據流源算符的時間。
  • 處理事件(processing time) 是每一個執行時間操作的算符的本地時間。

Event Time, Ingestion Time, and Processing Time

有狀態操作

儘管數據流中的很多操作一次只查看一個獨立的事件(比如事件解析器),有些操作卻會記錄多個事件間的信息(比如窗口算符)。 這些操作被稱爲 有狀態的 。

有狀態操作的狀態保存在一個可被視作嵌入式鍵/值存儲的部分中。狀態與由有狀態算符讀取的流一起被嚴格地分區與分佈。因此,只能訪問一個 keyBy() 函數之後的 keyed streams 的鍵/值狀態,並且僅限於與當前事件鍵相關聯的值。對齊流和狀態的鍵確保了所有狀態更新都是本地操作,以在沒有事務開銷的情況下確保一致性。這種對齊還使得Flink可以透明地重新分配狀態與調整流的分區。

State and Partitioning

容錯檢查點

Flink使用 流重放 與 Checkpoint 的結合實現了容錯。Checkpoint與每一個輸入流及其相關的每一個算符的狀態的特定點相關聯。一個流數據流可以可以從一個checkpoint恢復出來,其中通過恢復算符狀態並從檢查點重放事件以保持一致性(一次處理語義)

檢查點間隔是以恢復時間(需要重放的事件數量)來消除執行過程中容錯的開銷的一種手段。

流上的批處理

Flink將批處理程序作爲流處理程序的特殊情況來執行,只是流是有界的(有限個元素)。 DataSet 內部被視爲數據流。上述適用於流處理程序的概念同樣適用於批處理程序,除了一些例外:

  • DataSet API中的程序不使用檢查點。而通過完全地重放流來恢復。因爲輸入是有界的,因此這是可行的。這種方法使得恢復的成本增加,但是由於避免了檢查點,因而使得正常處理的開銷更小。
  • DataSet API中的有狀態操作使用簡化的im-memory/out-of-core數據結構,而不是鍵/值索引。
  • DataSet API引入了特殊的同步(基於superstep的)迭代,而這種迭代僅僅能在有界流上執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章