Kafka流處理內幕詳解
1.概述
流處理是一種用來處理無窮數據集的數據處理引擎。通常無窮數據集具有以下幾個特點:
- 無窮數據:持續產生的數據,它們通常會被稱為流數據。例如:銀行信用卡交易訂單、股票交易就、遊戲角色移動產生的數據等;
- 低延時:流數據通常都是實時處理,數據實時產生,然後流處理引擎實時處理流數據,因此延時很短。
2.內容
2.1 什麼是流處理
對於存儲在Kafka系統內的數據,Kafka系統提供了一種進行處理和分析的功能——流處理,它具有以下特性。
1. 是一個輕量級的類庫
Kafka流處理提供了一個非常輕量級的Java類庫,它能夠輕而易舉地集成到任意的Java應用程式中,打包和部署的方式也沒有特殊的要求。
2. 擁有良好的可擴展性和容錯性
Kafka流處理除了依賴Kafka系統外,對外界不存在任何依賴。在系統達到瓶頸時,Kafka流處理可以使用Kafka系統的分區機制,輕鬆地實現水平擴展來解決瓶頸問題。同時,通過記錄狀態(窗口操作、聚合操作等)來實現高效的操作。
3. 擁有豐富的應用介面
Kafka流處理對底層的應用介面進行了封裝,同時,對拓撲結構進行了高度抽象。
4. 具有靈活的彈性伸縮功能
在只讀取數據一次的情況下,流處理應用程式無需用戶介入,也能自動修改參數,實現應用程式的自動擴容和減容。
2.2 什麼是流式計算
通常情況下,流式計算與批處理計算會放在一起做比較分析。
(1)在流式計算模型中,數據的輸入是持續不斷的,這意味著永遠不知道數據的上限是多少,因此,計算產生的結果也是持續輸出的,流程如下圖所示。流式計算一般對實時性要求較高,為了提升計算效率,通常會採用增量計算來替代全量計算。
(2)在批處理計算模型中,通常數據上限是可知的,一般會先定義計算邏輯,然後進行全量計算,並將計算結果一次性輸出。流程如下圖所示。
2.3 為何需要流處理
在大數據生態圈中存在很多流處理系統或框架,下面介紹三個非常流行的開源流處理框架。
- Flink:一個對流數據和批次數據進行分散式處理的框架,它主要由Java程式碼實現。對於Flink而言,處理的主要是流數據,批次數據只是流數據的一個特例而已。當前Flink支援SQL語法來操作流數據。
- Spark Streaming:一種構建在Spark上的實時計算框架,用來處理流數據。Spark功能強大,同樣支援SQL語法來操作流數據。
- Storm:一個用於事件流的分散式處理框架,主要由Clojure實現。該框架的目標是將輸入流、處理、以及輸出模組結合在一起,並組建成一套有向無環圖。當前Storm也支援SQL語法來操作流數據。
既然已存在這些優秀的實時處理框架,為何Kafka還需要設計流處理呢?原因有以下幾點:
1. 簡單易用
Flink、Spark、Storm都屬於流式處理框架,而Kafka流處理是基於Kafka系統的流處理類庫,並非框架。
通常情況下,框架有固定的運行方式,用戶需要了解框架的執行流程,這使得學習成本增加。而Kafka流處理作為一個類庫,用戶可以直接調用具體的類,整個執行邏輯都在用戶的掌控之中,不會產生額外的學習成本。
2. 方便部署
Kafka流處理作為一個類庫,可以非常方便地集成到應用程式中,並且對應用程式的打包和部署沒有任何限制。
3. 資源使用率低
流式處理框架在啟動實例時會預分配系統資源,即使是應用程式實例,框架自身也需要佔用一部分系統資源。例如,一個Spark Streaming應用程式需要給Shuffle和Storage事先申請記憶體。
使用Kafka流處理不涉及框架實例的運行,所以不會額外佔用系統資源。
提示:
Shuffle可以理解為一個溝通數據連接的橋樑。
Storage負責把數據存儲到記憶體、磁碟或者堆外記憶體,有時還需要在其他節點創建副本來保存。
3.了解流處理架構
Kafka流處理使用Kafka系統的消費者類庫和生產者類庫來構建應用程式,並利用Kafka系統自身的特性來提供數據並行性、分散式協調性、容錯性、易操作性等,從而簡化用戶開發應用程式的步驟。具體工作流程如下圖所示:
Kafka流處理輸入的數據來源於Kafka系統中的業務主題,處理後的結果會存儲到Kafka系統中新的業務主題中。 上圖中,消費者程式和生產者程式並不需要用戶在應用程式中顯式地實例化,而是通過Kafka流處理根據參數來隱式地實例化和管理,這讓操作變得更加簡單。用戶只需關心核心業務邏輯(即上圖中的任務模組)的編寫,其他的都交由Kafka流處理來實現。
3.1 流分區與任務
Kafka流處理通過流分區來處理數據,內容包含存儲和傳輸數據。Kafka流處理使用分區和任務概念來作為並發模型中的邏輯單元。在並發環境中,通過分區數據來保證靈活性、可擴展性、高效性和容錯性。
1. 流分區的作用
在Kafka流處理中,每個流分區是完全而有序的數據隊列。這些有序數據記錄會映射到Kafka系統主題分區中。
流數據中映射的消息數據來自於Kafka系統主題。消息數據中鍵(Key)值是Kafka和Kafka流處理的關鍵,它決定了數據如何被路由到指定分區。
2. 任務的作用
一個應用程式可以被拆分成多個任務來執行。Kafka流處理會根據輸入流分區來創建固定數量的任務,每個任務分配一個輸入流分區列表。
任務是應用程式並行執行時的固定單元,因此分區對任務的分配不會造成影響。任務可以基於分配到的分區來實現相關處理流程,同時為每個分配到的分區保留一個緩衝區,並從這些緩衝區逐一地處理消息,這樣可以讓Kafka流處理的任務自動並行處理。
提示:
在一個子處理流程中,如果一個Kafka流處理應用程式指定了多個處理流程,則每個任務只實例化一個處理對象。
另外,一個處理流程可以被拆分為多個獨立的子處理流程,只要保證子處理流程與其他子處理流程沒有交集即可。通過這種方式可以讓任務之間保持負載均衡。
Kafka流處理不是一個資源管理器,而是一個類庫。 Kafka流處理可以運行在任何流處理應用程式中。應用程式的多個實例可以運行在同一台主機上,也可以分發到不同的主機進行執行。如果一個應用程式實例發生異常導致不可用,則該任務將會自動地在其他的實例上重新創建,並從相同的分區中繼續讀取數據。
3.2 執行緒模型
Kafka流處理允許用戶配置多個執行緒,並通過多執行緒來均衡應用程式中的任務數。每個執行緒的處理流程可以執行一個或者多個任務。
1. 執行緒模型的處理流程
下圖所示是使用一個執行緒來處理多個流任務。
啟動多個流執行緒或更多的應用程式,只需要複製執行流程即可。比如,將一份業務邏輯處理程式碼複製到不同的主機上進行執行。這樣做的好處是,通過多執行緒來並行處理不同Kafka系統主題分區中的數據,能提升處理效率。這些執行緒之間的狀態是不共享的。因此,不需要執行緒間的協作。這使得運行一個多並發的處理流程實例變得非常簡單。
2. 執行緒模型的優點
- 易擴展:對Kafka流處理應用程式進行擴展是很容易的,只需要運行應用程式的實例即可。
- 自動分配分區:Kafka流處理會監聽任務數量的變化,並自動給任務分配分區。
- 多執行緒:用戶在啟動應用程式時,可以根據Kafka系統輸入主題中的分區數來設置執行緒數。每個執行緒至少對應一個分區。
3. 多執行緒並發場景
假設有一個Kafka流處理應用程式,它從兩個業務主題(A和B)中讀取數據,每個業務主題都有3個分區。當用戶在一台主機上啟動一個應用程式實例,並設置執行緒數為2,最終會出現兩個Kafka流處理執行緒。
由於輸入主題A和輸入主題B的最大分區數均為3,所以Kafka流處理會默認將其拆分為3個任務,然後將合計的6個分區(主題A和主題B的分區總和)均勻地分布到3個任務中。
這種情況下,每個任務會同時從兩個分區中讀取數據。最終,這3個任務會被均勻地分布在兩個執行緒當中。兩個執行緒的作用分別如下。
執行緒1包含兩個任務,從四個分區(主題A的兩個分區和主題B的兩個分區)中讀取數據;
執行緒2包含一個任務,從兩個分區(主題A的一個分區和主題B的一個分區)中讀取數據。
隨著業務數據量的增加,需要對現有的應用程式進行拓展。實施的具體方案是,在另外一台主機上啟動該應用程式,並設置執行緒數為1。具體實現流程如下圖所示。
當前總分區數為6個,執行緒總數為3個。當任務被重新分配時,相同的分區、任務和存儲狀態,都會被移到新的執行緒,從而使應用程式達到負載均衡。
3.3 本地狀態存儲
Kafka流處理提供的狀態存儲機制,可用來保存和查詢應用程式產生的狀態數據。例如,在執行連接、聚合操作時,Kafka流處理會自動創建和管理這些狀態存儲。
下圖展示了兩個流處理任務,以及它們專用的本地狀態存儲。
在Kafka流處理應用程式中,每個流任務可以集成一個或多個本地狀態存儲,這些本地狀態存儲可以通過應用介面來進行存儲和查詢。同時,Kafka流處理也為本地狀態存儲提供了容錯機制和自動恢復功能。
3.4 容錯性
Kafka流處理繼承了Kafka系統主題分區的兩大能力——高可用能力、副本故障自動轉移能力。因而,在流數據持久化到Kafka系統主題時,即使應用程式失敗也會自動重新處理。
Kafka流處理中的任務利用Kafka系統客戶端提供的容錯機制來處理異常問題。如果某個任務在發生故障的主機上執行,則Kafka流處理會自動在應用程式的其他運行實例中重新啟動該任務。
每個狀態存儲都會維護一個更改日誌主題的副本,用來跟蹤狀態的更新。這些更改日誌主題也進行了分區,以便每個本地狀態存儲實例和訪問存儲的任務都有其專屬的更改日誌主題分區。在更該日誌主題上啟用日誌壓縮,可以方便、安全地清理無用數據,避免主題數據無限增長。
如果任務在一台主機上運行失敗,之後在另一台主機重新啟動,則Kafka流處理在恢復對新啟動的任務之前,通過回滾機制將關聯的狀態存儲恢復到故障之前,整個過程對於用戶來說是完全透明的。
需要注意的是,任務初始化所耗費的時間,通常取決於回滾機制恢復狀態存儲所用的時間。為了縮短恢復時間,用戶可以將應用程式配置為本地狀態的備用副本。當發生任務遷移時,Kafka流處理會嘗試將任務分配給已存在備用副本的應用程式實例,以減少任務初始化所耗費的時間。
提示:
可以通過設置屬性num.standby.replicas來分配每個任務的備用副本數。
4.總結
通過對Kafka Streams的研究,它的優勢可以總結為以下幾點。首先,它提供了輕量級並且易用的API來有效的降低流數據的開發成本,之前要實現這類處理,需要使用Spark Streaming,Storm,Flink,或者自己編寫Consumer。其次,它開發的應用程式可以支援在YARN,Mesos這類資源調度中,使用方式靈活。而對於非同步操作,不是很友好,需要謹慎處理;另外,對SQL語法的支援有限,需要額外開發。
5.結束語
這篇部落格就和大家分享到這裡,如果大家在研究學習的過程當中有什麼問題,可以加群進行討論或發送郵件給我,我會盡我所能為您解答,與君共勉!
另外,部落客出書了《Kafka並不難學》和《Hadoop大數據挖掘從入門到進階實戰》,喜歡的朋友或同學, 可以在公告欄那裡點擊購買鏈接購買部落客的書進行學習,在此感謝大家的支援。關注下面公眾號,根據提示,可免費獲取書籍的教學影片。