您好,登錄后才能下訂單哦!
這篇文章主要講解了“Flink編程模型是怎樣的”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Flink編程模型是怎樣的”吧!
Flink 提供幾種不同層次的抽象來開發 流/批(streaming/batch)進程
最低級的抽象僅提供狀態流(stateful streaming),它通過 Process Function (處理函數)內嵌在 DataStream API 中。它容許用戶自由地處理來自一個或多個流的事件,并且使用一致的容錯狀態。此外,用戶也可以給事件時間和處理時間注冊回調,使得進程可以實現復雜的計算。
實踐中,多數的應用進程不需要使用上述的低級的抽象,僅需要使用核心接口(Core API)來編碼,比如 DataStream API (數據流接口,有界/無界流) 和 DataSet API (數據集接口,有界數據集)。這些流暢的接口為數據處理提供了通用構建流程,諸如用戶指定的轉換(transformation)、連接(join)、聚合(aggregation)、窗口(window)、狀態(state)等不同形式。這些接口處理的數據類型在不同的編程語言中以類(class)的形式呈現。
低層次的處理函數(Process Function)與數據流接口(DataStream API)的交互,使得某些特定的操作可以抽象為更低的層次成為可能。數據集接口(DataSet API)在有界的數據集上提供額外的原始操作,例如循環和迭代(loops/iterations)。
表接口(Table API)使以表為中心的聲明性 DSL,可以動態地改變表(當展示流的時候)。Table API遵循(擴展)關系型模型:表附加了一個模式(schema)(類似于關系型數據庫中的表),此API提供了可比較的操作,例如select,project,join,group-by,aggregate等。Table API進程以聲明方式定義應該執行的邏輯操作,而不是準確地指定操作代碼。 盡管Table API可以通過各種類型的用戶定義函數進行擴展,但它的表現力不如Core API,但使用起來更簡潔(編寫的代碼更少)。 此外,Table API進程還會通過優化進程,在執行之前應用優化規則。
可以在表和DataStream/ DataSet之間無縫轉換,允許在進程中混合Table API以及DataStream和DataSet API。
Flink提供的最高級抽象是SQL。 這種抽象在語義和表達方面類似于Table API,但是將進程表示為SQL查詢表達式。 SQL抽象與Table API緊密交互,SQL查詢可以在Table API中定義的表上執行。
Flink進程的基本構建塊是流(streams)和轉換(transformations)。 (請注意,Flink的DataSet API中使用的DataSet也是內部流,稍后會詳細介紹。)從概念上講,流是(可能永無止境的)數據記錄流,而轉換是將一個或多個流作為輸入,并產生一個或多個輸出流的操作。
執行時,Flink進程映射到流數據流(streaming dataflows),由流(streams)和轉換運算符(operators)組成。 每個數據流都以一個或多個源(sources)開頭,并以一個或多個接收器(sinks)結束。 數據流類似于任意有向無環圖(DAGs, Directed acyclic graphs)。 盡管通過迭代結構允許特殊形式的循環,但為了簡單起見,我們將在大多數情況下對其進行掩飾簡化。
通常,進程中的轉換與數據流中的運算符之間存在一對一的對應關系。 但是,有時一個轉換可能包含多個轉換運算符。
源(soruces)和接收器(sinks)被記錄在 流連接器和 批處理連接器文檔中。 轉換(transformation)被記錄在 DataStream運算符和 DataSet轉換中。
Flink中的進程本質上是并行(parallel)和分布式的(distributed)。 在執行期間,流具有一個或多個流分區(stream partitions),并且每個運算符具有一個或多個運算子任務(operator subtasks)。 運算子任務彼此獨立,并且可以在不同的線程中執行,也可能是在不同的機器或容器上執行。
運算子任務的數量就是某個特定運算符的并行度(parallelism)。 流的并行度始終是其生成的運算符的并行度。 同一進程的不同運算符可能具有不同的并行級別。
流可以以一對一(或轉發)的模式或以重新分發的模式在兩個運算符之間傳輸數據:
一對一(One-to-one)流(例如,在上圖中的Source和map()運算符之間)保留元素的分區和排序。這意味著map()運算符的subtask[1]看到的元素與Source運算符的subtask[1]生成的元素順序相同。
重新分發(Redistributing)流(在上面的map()和keyBy/window之間,以及keyBy/window和Sink之間)重新分配流的分區。每個運算子任務將數據發送到不同的目標子任務,具體取決于所選的轉換。示例是keyBy()(通過散列鍵重新分區),broadcast()或rebalance()(隨機重新分區)。在重新分發的交換中,元素之間的排序僅保留在每對發送和接收子任務中(例如,map()的subtask[1]和keyBy/window的subtask[2])。因此,在此示例中,保留了每個鍵的排序,但并行度確實帶來了不同鍵的聚合結果到達sink的順序的不確定性。
有關配置和控制并行性的詳細信息,請參閱 并行執行的文檔。
聚合事件(如,counts,sums)在流上的工作方式與批處理方式不同。 例如,不可能計算流中的所有元素,因為流通常是無限的(無界)。 相反,流上的聚合(counts,sums等)由窗口(windows)限定,例如“在最后5分鐘內計數”或“最后100個元素的總和”。
Windows可以是時間驅動的(例如:每30秒)或數據驅動(例如:每100個元素)。 人們通常區分不同類型的窗口,例如翻滾窗口(tumbling windows)(沒有重疊),滑動窗口(sliding windows)(具有重疊)和會話窗口(session windows)(由不活動間隙打斷)。
當在流進程中引用時間(例如定義窗口)時,可以參考不同的時間概念:
事件時間(Event Time)是創建事件的時間。 它通常由事件中的時間戳描述,例如由生產傳感器或生產服務生成。 Flink通過 時間戳分配器(timestamp assigners)訪問事件時間戳。
接收時間(Ingestion Time)是事件在源操作符處進入Flink數據流的時間。
處理時間(Processing Time)是每個操作符執行基于時間的操作時的本地時間。
事件時間,接收時間和處理時間
雖然數據流中的許多運算只是一次查看一個單獨的事件(例如事件解析器),但某些運算會記住多個事件(例如窗口運算符)的信息。這些操作稱為stateful。
狀態運算的狀態可以被認為是由內嵌的鍵/值存儲來維護。狀態和狀態運算符讀取的流被嚴格地分區和分發。因此,只有在keyBy()函數之后才能在keyed stream上訪問鍵/值狀態,并且限制為與當前事件的鍵相關聯的值。對齊流和狀態的鍵可確保所有狀態更新都是本地操作,從而保證一致性而無需事務開銷。對齊操作還允許Flink重新分配狀態并透明地調整流分區。
狀態和分區
Flink使用stream replay和檢查點(checkpointng)的組合來實現容錯。檢查點與每個輸入流中的特定點以及每個運算符的對應狀態相關。通過恢復運算符的狀態并從檢查點重新執行(replay)事件,可以從檢查點恢復流數據流并保持一致性(exactly-once processing semantics)。
檢查點間隔是執行期間的容錯和恢復時間(需要重放的事件的數量)之間的折衷方法。
容錯的內部機制中的描述提供了有關Flink如何管理檢查點和相關主題的更多信息。有關啟用和配置檢查點的詳細信息,請參閱 檢查點API文檔。
Flink執行 批處理進程作為流進程的一種特殊情況,即流是有界的(有限數量的元素)。 DataSet在內部被視為數據流。因此,上述概念以相同的方式應用于批處理進程,并且它們適用于流進程,除了少數例外:
批處理進程的容錯不使用檢查點。通過完全重新執行流來進行恢復,因為輸入是有限的。這會使資源更多地用于恢復,且使得常規處理資源消耗更少,因為它避免了檢查點。
DataSet API中的有狀態操作(stateful operations)使用簡化的內存/核外(in-memory/out-of-core)數據結構,而不是鍵/值索引。
DataSet API引入了特殊的同步( superstep-based)迭代,這些迭代只能在有界流上進行。
感謝各位的閱讀,以上就是“Flink編程模型是怎樣的”的內容了,經過本文的學習后,相信大家對Flink編程模型是怎樣的這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。