姓名:閔聿寬
學號:16020188028
轉自:https://blog.csdn.net/silentwolfyh/article/details/82865579
【嵌牛導讀】數據流是我們如今在電子設計中常用的一種方法。下面介紹了一種新的FLINK-數據流編程模型
【嵌牛鼻子】FLINK數據流 編程模型
【嵌牛提問】FLINK-數據流編程模型具有怎樣的特點和優勢?
目錄:
Flink提供了不同級別的抽象來開發流/批處理應用程序。
1) 低層級的抽象
最低層次的抽象僅僅提供有狀態流。它通過Process函數嵌入到DataStream API中。它允許用戶自由地處理來自一個或多個流的事件,并使用一致的容錯狀態。此外,用戶可以注冊事件時間和處理時間回調,允許程序實現復雜的計算。
2) 核心API
在實踐中,大多數應用程序不需要上面描述的低級抽象,而是對核心API進行編程,比如DataStream API(有界或無界數據流)和DataSet API(有界數據集)。這些API提供了用于數據處理的通用構建塊,比如由用戶定義的多種形式的轉換、連接、聚合、窗口、狀態等。在這些api中處理的數據類型以類(class)的形式由各自的編程語言所表示。
低級流程函數與DataStream API集成,使得只對某些操作進行低級抽象成為可能。DataSet API為有界數據集提供了額外的原語,比如循環或迭代。
3) Table API
Table API是一個以表為中心的聲明性DSL,其中表可以動態地改變(當表示流數據時)。表API遵循(擴展)關系模型:表有一個附加模式(類似于關系數據庫表)和API提供了類似的操作,如select, project, join, group-by, aggregate 等。Table API 程序以聲明的方式定義邏輯操作應該做什么而不是指定操作的代碼看起來如何。雖然Table API可以通過各種用戶定義函數進行擴展,但它的表達性不如核心API,但使用起來更簡潔(編寫的代碼更少)。此外,Table API程序還可以在執行之前通過應用優化規則的優化器。可以無縫地在Table API和DataStream/DataSet API之間進行切換,允許程序將Table API和DataStream和DataSet API進行混合使用。
4) Sql層
Flink提供的最高級別抽象是SQL。這種抽象在語義和表示方面都類似于Table API,但將程序表示為SQL查詢表達式。SQL抽象與表API密切交互,SQL查詢可以在表API中定義的表上執行。
Flink程序的基本構建模塊是streams 和 transformations 。(請注意,Flink的DataSet API中使用的數據集也是內部流——稍后將對此進行詳細介紹。)從概念上講,streams 是數據記錄的(可能是無限的)流,而transformations是將一個或多個流作為輸入并產生一個或多個輸出流的操作。
執行時,Flink程序被映射到流數據流,由streams 和 transformations 操作符組成。每個數據流以一個或多個sources開始,以一個或多個sinks結束。數據流類似于任意有向無環圖(DAGs)。雖然通過迭代構造允許特殊形式的循環,但為了簡單起見,我們將在大多數情況下忽略這一點。
通常在程序中的transformations和數據流中的操作之間是一對一的對應關系。然而,有時一個transformations可能包含多個transformations操作。
在streming連接器和批處理連接器文檔中記錄了Sources 和 sinks。在DataStream運算和數據集transformations中記錄了transformations。
Flink中的程序本質上是并行的和分布式的。在執行期間,流有一個或多個流分區,每個operator?有一個或多個operator subtasks(操作子任務)。operator subtasks相互獨立,在不同的線程中執行,可能在不同的機器或容器上執行。
operator subtasks的數量是特定運算符的并行度。一個流的并行性總是它的生產操作符的并行性。同一程序的不同運算符可能具有不同級別的并行性。
流可以在兩個操作符之間以一對一(或轉發)模式傳輸數據,也可以在重新分配模式中傳輸數據:
One-to-one?流(例如上圖中Source和map()運算符之間的流)保持元素的分區和順序。這意味著map()操作符的subtask[1]將看到與源操作符的subtask[1]生成的元素相同的順序。
Redistributing?流(如上面的map()和keyBy/window之間,以及keyBy/window和Sink之間)改變流的分區。每個操作符子任務根據所選的轉換將數據發送到不同的目標子任務。例如keyBy()(通過散列鍵來重新分區)、broadcast()或balanced()(隨機重新分區)。在重分發交換中,元素之間的順序只保留在每一對發送和接收子任務中(例如map()的子任務[1]和keyBy/window的子任務[2])。因此,在本例中,每個鍵中的順序都是保留的,但是并行性確實引入了關于不同鍵的聚合結果到達sink的順序的不確定性。
聚合事件(例如計數、求和)在流上的工作方式與批處理不同。例如,不可能計算流中的所有元素,因為流通常是無限的(無界的)。相反,流上的聚合(計數、求和等)是由窗口限定作用域的,例如“過去5分鐘的計數”或“最后100個元素的總和”。
Windows可以是時間驅動(示例:每30秒)或數據驅動(示例:每100個元素)。一個典型的方法是區分不同類型的窗口,比如翻滾窗戶(沒有重疊)、滑動窗口(有重疊)和會話窗口(中間有一個不活躍的間隙)。
? ? ? ?當提到流程序中的時間(例如定義窗口)時,可以指不同的時間概念:
事件時間 : 是創建事件的時間。它通常由事件中的時間戳描述,例如由生產傳感器或生產服務附加。Flink通過時間戳轉讓者訪問事件時間戳。
攝入時間 : 在source操作符中一個事件進入Flink數據流的時間。
處理時間 : 是執行基于時間的操作的每個操作符的本地時間。
雖然一個數據流中有許多操作但只看作一個單獨的事件(例如事件解析器),但是一些操作記住了跨多個事件的信息(例如窗口操作符)。這些操作稱為有狀態操作。
有狀態操作的狀態被維護在可以認為是嵌入式鍵/值存儲中。狀態與有狀態操作符讀取的流一起被嚴格地分區和分布。因此,在keyBy()函數之后,只能在鍵控流上訪問鍵/值狀態,并且只能訪問與當前事件的鍵相關聯的值。對齊流和狀態的鍵確保所有的狀態更新都是本地操作,保證一致性而不增加事務開銷。這種對齊還允許Flink透明地重新分配狀態和調整流分區。
(EventTime是信息自帶的時間,再進入消息隊列,IngestionTime是進入Flink的時間,Processing是進入Operator的時間)
Flink通過流回放和檢查點的組合實現了容錯。檢查點與每個輸入流中的特定點以及每個操作符的對應狀態相關。通過恢復操作符的狀態并從檢查點重新播放事件,流數據流可以在檢查點恢復,同時保持一致性(準確地說是一次處理語義)。
檢查點間隔是在執行期間用恢復時間(需要重放的事件數量)來權衡容錯開銷的一種方法。
? ? ? ?Flink執行批處理程序作為流程序的特殊情況,其中流是有界的(有限的元素數量)。數據集在內部被視為數據流。因此,上述概念同樣適用于批處理程序,也適用于流程序,但有少數例外:
批處理程序的容錯不使用檢查點。恢復通過完全重放流來實現。這是可能的,因為輸入是有界的。這將使成本更多地用于恢復,但使常規處理更便宜,因為它避免了檢查點。
數據集API中的有狀態操作使用簡化的內存/核心外數據結構,而不是鍵/值索引。
DataSet API引入了特殊的synchronized(基于超步的)迭代,這只能在有界的流上實現。有關詳細信息,請查看迭代文檔。