這個問題其實咱們大部分時候是沒有考慮過的,大多數,咱們是把流式處理和實時計算放在一塊兒來講的。咱們先來了解下,什麼是數據流。數據庫
流式處理就是指實時地處理一個或多個事件流。它是一種編程範式。其餘編程領域,主要有3種編程範式:編程
流的定義不依賴某個框架,只要儲蓄從一個無邊界數據集中讀取數據,並對它們進行處理生成結果,就是進行流式處理。重點是:整個過程必須是持續的。設計模式
上述咱們已經說過了,數據流都是有序的。某一時刻的數據是肯定的。時間是流式處理中很是重要的概念。大部分流式應用的操做都是基於時間窗口的。緩存
流式系統通常包含如下幾個時間概念(熟悉Flink的同窗應該會很熟悉):網絡
若是流式處理是來一個事件就處理一個事件,那麼流式處理就很簡單。但若是操做中包含了多個事件,流式處理就有意思了。例如:咱們想在流式處理中統計北京用戶的訂單數量、消費金額等等。此時,就不能光處理單個事件了,咱們須要獲取更多的事件。事件與事件之間的信息就稱之爲狀態。例如簡單的,求某個類型的訂單數等。併發
這些狀態通常就保存在流式處理程序本地變量(本地內存)中,例如:使用HashMap來保存計數。但這種作法是很不可靠的,流式處理處理的是無界數據集,一旦應用程序出現異常,就會出現狀態丟失,這是咱們說不能接受的。因此,每一種流式計算框架都會很當心地持久化狀態。若是應用程序重啓,須要將這些數據恢復。負載均衡
流式處理通常包含兩種狀態:框架
大部分針對流的操做都是基於時間窗口的。例如:計算一週內銷量最好的產品。兩個流的合併也是基於時間窗口的。流式系統會合併發生在相同時間段上的事件。窗口是有類型的。如下幾點是咱們設計窗口須要考慮的:性能
下面這張圖,說明了滾動窗口與滑動窗口的區別。線程
滾動窗口:假設窗口的大小爲5分鐘,這裏肯定的3個時間窗口
滑動窗口:假設每分鐘滑動一次,那麼這個時候會有5個時間窗口,計算結果會發生重疊
這是流式處理最基本的模式。這種模式也叫:map或filter模式。常常被用來過濾無用的事件或者用於轉換事件。
這種模式,應用程序讀取流中的數據,修改數據,而後把事件生成到另外一個流上。這一類應用程序無需在程序內部維護狀態,每個事件都是獨立處理的。這種錯誤恢復和進行負載均衡都很容易。由於無需進行狀態恢復操做。
大部分流式處理應用關係如何聚合數據。特別是:基於時間窗口進行聚合。例如:找到天天最低、最高的交易價格。要實現這種操做,就須要維護流的狀態。例如:咱們須要將最小值、最大值保存下來,用它們與每個新值對比。這類操做,能夠經過本地狀態來實現。例如:每個分組都維護本身分組的狀態。
一旦流式處理中包含了本地狀態,就須要解決如下問題。
有些時候,咱們要經過全部可用的數據來得到結果。例如:要發佈天天的「前10支」股票,這10支股票須要從天天的交易股票中挑選出來。若是僅僅在單個實例上處理是不夠的,由於10支股票分佈在多個實例上。
此種,咱們分爲多個階段來處理。
一、計算每支股票當天的漲跌。這個計算能夠在每一個實例上執行
二、將結果寫入到單個分區
三、再用一個實例找出當天的前10支股票
這一類操做就與MapReduce很像了。
有時候,流式處理須要將外部數據和流集成在一日。例如:外部數據中保存了一些規則、或者將完整完整地用戶信息拉取到流中。
這種case最大的問題,外部查找會帶來嚴重的延遲,通常在 5-15 ms之間,這在不少狀況下是不可行的。並且,外部系統也沒法承受這種額外的負載——流式處理系統每秒能夠處理10-50W個事件,而數據庫正常狀況下每秒只能處理1W個事件,因此須要伸縮性更強的解決方案。
爲了獲取更好的性能和更強的伸縮性,須要將外部數據庫的信息緩存到流式處理應用中。但考慮如下問題:
如何保證緩存裏的數據是最新的?
若是刷新太頻繁,仍然會對數據庫形成很大壓力,緩存也就無用了。
若是刷新不及時,那麼流式處理中所用的數據就會過期。
若是可以捕捉數據庫的變動事件,並造成事件流,流式處理做業就能夠監聽事件流,並及時更新緩存。捕捉數據庫的變動事件並造成數據流,這個過程稱爲CDC(Change Data Capture)。例如:咱們能夠經過Canal來捕獲MySQL數據庫的變化、能夠經過ogg來捕獲Oracle數據庫的變化
有時候須要鏈接兩個真實的事件流。要鏈接兩個流,就是鏈接全部的歷史事件(將兩個妞中具備相同鍵、發生在相同時間窗口內的事件匹配起來),這種流和流的鏈接稱爲:基於時間窗口的鏈接(windowed-join)。鏈接兩個流,一般包含一個滑動時間窗口。
無論對於流式處理、仍是傳統的ETL系統,處理亂序事件都是一個挑戰。物聯網領域常常發生亂序事件:一個移動設備斷開Wifi鏈接幾個小時,在從新連上WiFi後,將幾個小時堆積的事件一併發出去。要讓流式處理應用處理好這些場景,須要作到幾下:
該重要模式是從新處理事件:
第一種狀況,須要Kafka將事件流長時間地保存在可伸縮的數據存儲中
第二種狀況,須要應用程序回到輸入流的起始位置開始處理,同時重置本地狀態,還要清理以前的輸出流。這種方式處理起來比較困難。建議仍是使用第一種方案。
參考文獻:
《Kafka全文指南》