參考書籍編程
Stream Processing with Apache Flinkhttps://www.oreilly.com/library/view/stream-processing-with/9781491974285/緩存
《基於Apache Flink的流處理》https://book.douban.com/subject/34912177/安全
注:本文主要是針對《基於Apache Flink的流處理》的筆記服務器
1-8章筆記下載地址網絡
本章的目標是介紹流處理的基本概念以及對其處理框架的要求。session
Dataflow程序一般表示爲有向圖,併發
圖2-1顯示了一個數據流程序,它從文章的輸入流中提取並計數一些標籤。app
像圖2-1中的數據流圖被稱爲邏輯圖,由於它們傳達了計算邏輯的高級視圖。爲了執行數據流程序,它的邏輯圖被轉換成物理Dataflow圖,該圖詳細說明了程序是如何執行的。例如,若是咱們使用分佈式處理引擎,每一個 算子可能有幾個並行任務在不一樣的物理機器上運行。負載均衡
圖2-2顯示了圖2-1的邏輯圖的物理數據流圖。在邏輯Dataflow圖中,節點表明算子,而在物理Dataflow圖中,節點表明任務。每一個任務負責計算一部分的輸入數據。框架
能夠以不一樣的方式利用數據流圖中的並行性。
首先,能夠對某個算子的輸入數據進行分區,並在數據子集上並行執行相同操做的任務。這種類型的並行稱爲數據並行。數據並行很是有用,由於它容許將大量計算數據分佈到多個不一樣的物理節點上並行執行。
其次,可讓不一樣算子的任務 並行執行相同或不一樣數據的計算。這種類型的並行稱爲任務並行。使用任務並行,能夠更好地利用集羣的計算資源。
數據交換策略定義了數據項如何被分配給物理Dataflow圖中的不一樣任務。在這裏,咱們簡要介紹一些常見的數據交換策略,如圖2-3所示。
下面看看如何將Dataflow的概念運用到並行數據流處理中。咱們先給出數據流的定義:數據流是一個長度可能無限長的事件序列
數據流的例子以下:監控器產生的監控數據、傳感器產生的測量數據、信用卡交易數據、氣象站觀測數據、搜索引擎搜索記錄等
對於批處理應用程序,咱們一般關心做業的總執行時間,或者咱們的處理引擎讀取輸入、執行計算和寫回結果須要多長時間。因爲流應用程序連續運行,而且輸入多是無限的,所以在流處理中沒有總執行時間的概念。取而代之的是,流處理必須儘量快地爲傳入數據提供結果(延遲),同時還要應對很高的事件輸入速率(吞吐)。咱們用延遲和吞吐來表示這兩方面的性能需求。
延遲表示處理一個事件所需的時間。本質上,它是接收事件到在輸出中看到事件處理效果的時間間隔。
在數據流中,延遲以時間爲單位進行衡量,例如毫秒。根據應用程序的不一樣,可能會關心平均延遲、最大延遲或百分比延遲。例如,10ms的平均延遲意味着平均在10ms內處理事件。或者,10毫秒的95%延遲值意味着95%的事件在10毫秒內獲得處理。
像Apache Flink這樣的現代流處理引擎能夠提供低至幾毫秒的延遲。
吞吐量是對系統處理能力的一種度量——它的處理速率。也就是說,吞吐量告訴咱們系統每單位時間能夠處理多少個事件。
須要注意的是,處理的速率取決於事件到達速率;低吞吐量不必定表示性能差。在流式系統中,一般但願確保系統可以處理最大的預期事件到達速率。也就是說,主要關心的是肯定峯值吞吐量,即系統處於最大負載時的性能限制。
一旦事件到達速率超過了預期的最大值,咱們就不得不開始緩衝事件。若是系統繼續以超過其處理能力的接收速率接收數據,緩衝區可能會變得不可用,數據可能會丟失。這種狀況一般被稱爲背壓。
此時,應該清楚的是,延遲和吞吐 不是獨立的指標。
下降延遲可提升吞吐量。若是一個系統能夠更快地執行操做,它能夠在相同的時間內執行更多的操做。而一個很好的方式就是並行處理
流處理引擎一般提供一組內置操做來接收、轉換和輸出數據流。這些操做能夠用來構成Dataflow圖來表明流式應用的邏輯。在本節中,咱們將介紹最常見的流式操做。
操做能夠是無狀態的,也能夠是有狀態的。
數據接入和數據輸出操做容許流處理器與外部系統通訊。
數據接入是從外部系統 獲取原始數據並將其轉換爲適合處理格式的操做。實現數據接入邏輯的算子稱爲數據源。
數據輸出是以適合外部系統使用的形式產生輸出的操做。實現數據輸出的算子稱爲數據匯,
轉換操做是單程操做(single-pass),每一個事件都獨立處理。操做一個接一個地處理事件,並對事件數據進行一些轉換,產生一個新的輸出流。通常來講,轉換操做比較簡單,不用維護內部狀態
轉換操做的算子能夠接受多個輸入併產生多個輸出流。他們還能夠經過將一個流分紅多個流或將多個流合併成一個流來修改數據流圖的結構。
滾動聚合是針對每一個輸入事件不斷更新的聚合操做,好比總和、最小值和最大值。聚合操做是有狀態的,並將當前狀態與傳入事件相結合以生成新的聚合值。圖2-5顯示了一個滾動最小聚合。操做符保持當前的最小值,並針對每一個傳入事件相應地更新它。
轉換和滾動聚合 每次處理一個事件,以生成輸出事件並更新狀態。可是,有些操做必須收集和緩存事件。例如求中位數的函數。爲了在無限流上高效地計算這些操做,須要限制這些操做維護的數據量。在本節中,咱們將討論窗口操做。
窗口還支持在數據流上進行一些有趣的查詢。例如:若是有一個爲司機提供實時交通訊息的應用程序。在這個場景中,您想知道在過去幾分鐘內某個位置是否發生了擁堵。這時候咱們只關注過去幾分鐘這個窗口的數據。
窗口操做不斷地從一個無界事件流中建立 長度有限的事件集(稱爲桶),並讓咱們對這些桶 執行計算。事件一般根據數據屬性或時間分配到桶中。窗口的行爲由一組策略定義。窗口策略決定什麼時候建立新的存儲桶,將哪些事件分配給哪些存儲桶,以及什麼時候計算桶中的數據。窗口策略的指定能夠基於時間、數量或其餘數據屬性
下面介紹常見的窗口類型的語義
滾動窗口將事件分配到長度固定的不重疊的桶中。當窗口邊界經過時,全部事件都被發送到一個計算函數進行處理。基於計數的滾動窗口定義了在觸發評估以前收集了多少事件。圖2-6顯示了一個基於計數的滾動窗口,它將輸入流分到四個元素組成的桶。基於時間的滾動窗口定義了桶中事件的時間間隔。圖2-7顯示了一個基於時間的滾動窗口,它將事件收集到桶中,並每10分鐘觸發一次計算。
滑動窗口將事件分配到固定大小的容許互相重疊的桶中。所以,一個事件 可能屬於多個桶。咱們經過指定桶的長度和滑動間隔來定義滑動窗口。圖2-8中的窗口長度爲4,滑動間隔爲3。
會話窗口在常見的現實場景中很是有用,在這些場景中,滾動窗口和滑動窗口都不能應用。考慮一個分析在線用戶行爲的應用程序。在這樣的應用程序中,咱們但願未來自同一會話的事件分到一組。
會話窗口根據會話間隔(session gap)對事件進行分組,會話間隔定義了認爲會話已關閉的非活動時間。(也就是若是用戶在很長的一段時間內沒有與服務器通訊就認爲他的會話已經關閉了)
窗口操做與流處理中的兩個主要概念密切相關:時間語義和狀態管理。
處理時間是機器上本地時鐘的時間。處理時間窗口包括在一段時間內** 碰巧到達窗口的全部事件,由機器的本地時鐘測量。如圖2-12所示
事件時間是流中的事件實際發生的時間。事件時間經過附加到流事件的時間戳來判斷。
圖2-13顯示:即便事件有延遲,事件時間窗口也能準確地把事件分配到正確的窗口中,從而反映事情發生的真實狀況。
不管數據流的處理速度有多快,事件到達算子的順序是怎樣的,事件時間窗口的計算將產生相同的結果。
經過依賴事件時間,即便是在無序數據的狀況下,咱們也能夠保證結果的正確性。此外,當與可重放的流結合時,時間戳的肯定性使你可以回到過去。也就是說,你能夠重放一個流並分析歷史數據,就像事件是實時發生的同樣。
到目前爲止,在咱們關於事件時間窗口的討論中,咱們忽略了一個很是重要的方面:咱們如何決定事件時間窗口的觸發時機(何時中止收集並開始計算)?也就是說,咱們要等多久才能肯定咱們已經收到了某個時間點以前發生的全部事件?考慮到分佈式系統的不可預測性和由外部帶來的各類延遲,這些問題沒有絕對正確的答案。
水位線(watermark)是一種全局進度度量,它是一個時間點。它代表咱們確信這個時間點以前的事件所有到達了。本質上,水位線提供了一個邏輯時鐘,通知系統當前的事件時間。當操做員收到時間爲T的水位線時,能夠假設不會再收到時間戳小於T的事件。水位線對於事件時間窗口和處理無序事件的算子都是必不可少的。
水位線提供告終果可信度和延遲之間trade-off。
流處理系統會提供某種機制來處理在水位線以後到達的事件。
此刻你可能會想,既然事件時間解決了咱們全部的問題,爲何咱們還要去關心處理時間?
事實是,在某些狀況下,處理時間確實頗有用。
狀態在數據處理中無處不在。任何複雜一點的計算都須要它。爲了產生結果,函數在一段時間或多個事件上累積狀態(例如,計算彙集或檢測模式)。有狀態算子使用傳入事件和內部狀態來計算它們的輸出並更新狀態。
在連續運行的流做業中,狀態在事件之間是持久的,咱們能夠在編程模型中將其做爲一級公民公開。而在以前的批處理中,後一個批次的數據是看不到前一個批次的數據的。
因爲流操做引擎有可能處理的是無限流,所以應當心不要讓內部狀態無限增加。爲了限制狀態的大小,算子一般會對到目前爲止看到的事件進行某種總結或概要。這樣的摘要能夠是計數、總和、迄今爲止所看到的事件的抽樣、窗口緩衝區。
支持有狀態算子會帶來不少實現上的挑戰:
流式做業中的算子狀態很是重要,應防止出現故障。若是狀態在故障期間丟失,恢復後的結果將是不正確的。流處理引擎不只須要保證在出現任務故障時能夠正常運行,還須要保證結果和算子狀態的正確性。
對於輸入流中的每一個事件,任務執行如下步驟:
在這些步驟中的任何一個均可能發生故障,系統必須清楚地定義其在每種故障場景中的如何處理。例如,一個定義完整的流式處理系統須要明確如下問題:若是任務在第一步失敗,事件會丟失嗎?若是在更新了內部狀態後失敗了,恢復後還會再更新嗎?而在上面這些狀況下,輸出仍是正確的嗎?
在批處理場景中,全部這些問題都獲得了回答,由於批處理做業能夠簡單地從頭開始從新啓動。所以,沒有事件丟失,狀態徹底是從零開始創建的。然而,在流處理中,這些問題很棘手。流式系統經過提供結果保障(result guarantee)來定義它們在出現故障時的行爲。接下來,咱們回顧了現代流處理引擎提供的幾種不一樣級別的結果保障。
當任務失敗時,最簡單的方法就是不作任何事情來恢復丟失的狀態和重放丟失的事件。至多一次只保證每一個事件至多處理一次。換句話說,系統能夠簡單地丟棄事件,不作任何事情來確保結果的正確性。這種類型的保障也被稱爲「無保障」,由於即便是系統丟棄全部事件也能夠提供這種保證。
在大多數現實世界的應用程序中,人們指望事件不會丟失。這種類型的保證被稱爲至少一次,這意味着全部事件都將被處理,而且其中一些事件有可能被處理屢次。若是應用程序的正確性僅取決於信息的完整性,重複處理多是能夠接受的。
爲了確保至少一次這種結果保障,須要有一種方法來重放(replay)事件——要麼從源(source),要麼從某個緩衝區(buffer)。
下面介紹兩種保證至少一次的方式
精確一次是最嚴格的保證,也很難實現。它意味着不只不會有事件丟失,並且每一個事件只容許處理一次。從本質上來講,精確一次意味着咱們的應用程序將提供徹底正確的結果,就好像從未發生過失敗同樣。
精確一次是以致少一次爲前提的,所以數據重放機制必不可少。
並且在故障恢復以後,處理引擎應該知道一個事件的更新是否已經反映在狀態上。有兩種實現方式:
事務性更新是實現這一結果的一種方式,可是它們會致使大量的性能開銷。
相反,Flink使用輕量級快照機制來實現一次結果保證
端到端保證指的是整個數據處理流水線上的結果正確性。流水線上的每一個組件都提供本身的保證,完整管道的端到端保證將由全部組件中最弱的那個組件來決定。有時候弱的保障可能會表現出強的語義,好比,你使用至少一次來求最大值或者最小值,管道的其餘組件都使用精確一次,那麼這個管道也是端到端精確一次的。