如何為Kafka集群選擇合適的Topic/Partitions數量
- 2020 年 2 月 19 日
- 筆記
本文介紹一些與本問題相關的一些重要決策因素,並提供一些簡單的計算公式
越多的分區可以提供更高的的吞吐
首先要明白,在kafka中,單個partition是kafka並行操作的最小單元,在producter和broker端,向每一個分區寫入數據是完全可以並行的,此時,可以通過加大硬體資源的利用率來提升系統的吞吐量,例如對數據進行壓縮,在consumer端,kafka只允許單個partition的數據被一個consumer執行緒消費,因此,在consumer端,每個consumer group內部的consumer並行度完全依賴與被消費的分區數量。綜上,通常情況下,在一個kafka集群中,partition的數量越多,意味這可以到達的吞吐量越大。
分區數量的計算:
我們可以粗略的通過吞吐量來計算kafka集群的分區數量,假設對於單個partition,producer端可達吞吐量為p,consumer端可達吞吐量為c,期望的目標吞吐量為t,那麼集群所需要的partition數量至少為max(t/p,t/c),在producter端,單個分區的吞吐量大小會收到批量大小,數據壓縮方法,確認類型(同步非同步),複製因子等配置參數的影響,經過測試,在producer端,單個partition的吞吐量通常在10MB/s左右,在consumer端,單個partition的吞吐依賴於consumer端每個消息的應用邏輯處理速度。
隨著時間的推移,我們能夠對分區的數量進行添加,但是對於基於key的hash來分區的topic,我們最好根據未來1到2年的目標吞吐量來設計kafka的分區數量。
越多的分區需要打開更多的本地文件句柄
在kafka的broker中,每個分區都會對照著文件系統的一個目錄,在kafka的數據日誌文件目錄中,每個日誌數據段都會分配兩個文件,一個索引文件和一個數據文件,每個broker會為每個日誌段文件打開一個index文件和一個數據文件句柄,因此,隨著partition的增多,需要底層作業系統配置更高的文件句柄數量限制。這更多的是一個配置問題。
更多的分區會導致更高的不可用性
kafka通過多副本複製技術,實現kafka集群的高可用和穩定性,每個partition都會有多個數據副本,每個副本分別存在於不同的broker,所有的數據副本中,有一個數據副本為leader,其他的數據副本為follower,在kafka集群內部,所有的數據副本皆採用自動化的方式進行管理,並且確保所有的數據副本的數量皆保持同步狀態,不論是producer端還是consumer端發往partition的請求,皆通過leader數據副本所在broker來處理,當broker發生故障時,對於leader數據副本在該broker的所有partition將暫時不可用,kafka將會自動在其他的數據副本中選擇一個leader,用於接受客戶端的請求,這個過程由kafka 的 controller節點的broker自動完成。主要是從zk讀取和修改受影響partition的一些元資訊。對zookeeper的所有操作都是由kafka controller來完成的。
通常情況下,當一個broker有計劃的停止服務時,那麼controller會在服務停止之前,將該broker上的所有leader一個一個的移走,由於單個leader的移動時間大約只需要幾毫秒,因此從客戶層面看,有計劃的服務停機只會導致系統在很小時間窗口中不可用。
然後,當broker非計劃的停止服務時,例如kill -9 ,系統的不可用時間窗口將會與受影響的partition數量有關。假如,一個2節點的kafka集群中存在2000個partition,每個partition有2個數據副本。當其中一個broker非計劃的宕機後,所有1000個partition同時變的不可用。假設每個partition有5毫秒的時間恢復,1000個就要5秒的恢復時間,如果更不幸的是宕機的broker是controller節點時,在這種情況下,新leader節點的選舉在controller節點恢復之前是不會啟動的,controller節點的錯誤恢復將會自動進行,但是新的controller節點需要從zookeeper中讀取每個partition的元資訊用戶初始化數據。加入從zk讀取一個partition要用2ms,有10000個partition的話,則controller的恢復將會增加約20s。所以最好將每個broker的partition的數據限制在2000到4000,每個kafka集群中partition的數量限制在10000以內。
越多的分區可能增加端對端的延遲
kafka端對端延遲定義為producer端發布消息到consumer端接收消息所需要的時間。即consumer接收消息的時間減去producer發布消息的時間。kafka只有在消息提交之後,才會將消息暴露給消費者。例如消息在所有in-sync副本列表同步複製完成後才會暴露。因此in-sync副本複製所花的時間是kafka端對端延遲的主要部分。在默認情況下,每個broker從其他broker節點進行數據副本複製時,該broker節點只會為此工作分配一個執行緒,該執行緒需要完成該broker所有partition數據複製。將1000個partition從一個broker複製到另一個broker所帶來的時間延遲約為20ms,這意味著端對端的延遲至少是20ms,這樣的延遲對一些實時應用需求來說顯得過長。要麼可以通過加大kafka集群來緩解。將1000個分區leader放到1個broker和放到10個broker,他們之間的延遲是存在差異的。10個broker節點的集群中,每個broker節點平均需要處理100個分區的數據複製,延遲將下降。
如果十分在意消息延遲的問題,限制每個broker節點的partition數量是一個很好的主意:對於b個broker節點和複製因子為r的kafka集群。整個kafka集群的partition數量最好不超過100 * b * r。
總結
kafka集群中越多的partition會帶來越高的吞吐量,但是我們必須意識到集群的partition總量多大或者單個broker節點partition過多,都會對系統的可用性和消息延遲帶來潛在的影響。