Flink提供了不一樣級別的抽象來開發流/批處理應用程序。數據庫
1) 低層級的抽象
最低層次的抽象僅僅提供有狀態流。它經過Process函數嵌入到DataStream API中。它容許用戶自由地處理來自一個或多個流的事件,並使用一致的容錯狀態。此外,用戶能夠註冊事件時間和處理時間回調,容許程序實現複雜的計算。編程
2) 核心APIapi
在實踐中,大多數應用程序不須要上面描述的低級抽象,而是對核心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)。雖然經過迭代構造容許特殊形式的循環,但爲了簡單起見,咱們將在大多數狀況下忽略這一點。spa
一般在程序中的transformations和數據流中的操做之間是一對一的對應關係。然而,有時一個transformations可能包含多個transformations操做。
在streming鏈接器和批處理鏈接器文檔中記錄了Sources 和 sinks。在DataStream運算和數據集transformations中記錄了transformations。.net
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個元素)。一個典型的方法是區分不一樣類型的窗口,好比翻滾窗戶(沒有重疊)、滑動窗口(有重疊)和會話窗口(中間有一個不活躍的間隙)。
當提到流程序中的時間(例如定義窗口)時,能夠指不一樣的時間概念:
雖然一個數據流中有許多操做但只看做一個單獨的事件(例如事件解析器),可是一些操做記住了跨多個事件的信息(例如窗口操做符)。這些操做稱爲有狀態操做。
有狀態操做的狀態被維護在能夠認爲是嵌入式鍵/值存儲中。狀態與有狀態操做符讀取的流一塊兒被嚴格地分區和分佈。所以,在keyBy()函數以後,只能在鍵控流上訪問鍵/值狀態,而且只能訪問與當前事件的鍵相關聯的值。對齊流和狀態的鍵確保全部的狀態更新都是本地操做,保證一致性而不增長事務開銷。這種對齊還容許Flink透明地從新分配狀態和調整流分區。
(EventTime是信息自帶的時間,再進入消息隊列,IngestionTime是進入Flink的時間,Processing是進入Operator的時間)
Flink經過流回放和檢查點的組合實現了容錯。檢查點與每一個輸入流中的特定點以及每一個操做符的對應狀態相關。經過恢復操做符的狀態並從檢查點從新播放事件,流數據流能夠在檢查點恢復,同時保持一致性(準確地說是一次處理語義)。
檢查點間隔是在執行期間用恢復時間(須要重放的事件數量)來權衡容錯開銷的一種方法。
Flink執行批處理程序做爲流程序的特殊狀況,其中流是有界的(有限的元素數量)。數據集在內部被視爲數據流。所以,上述概念一樣適用於批處理程序,也適用於流程序,但有少數例外: