如何為Kafka叢集選擇合適的Topic/Partitions數量
這是許多kafka
使用者經常會問到的一個問題。本文的目的是介紹與本問題相關的一些重要決策因素,並提供一些簡單的計算公式。
越多的分割槽可以提供更高的吞吐量
首先我們需要明白以下事實:在kafka
中,單個patition
是kafka
並行操作的最小單元。在producer
和broker
端,向每一個分割槽寫入資料是可以完全並行化的,此時,可以通過加大硬體資源的利用率來提升系統的吞吐量,例如對資料進行壓縮。在consumer
段,kafka只允許單個partition
的資料被一個consumer
執行緒消費。因此,在consumer
端,每一個Consumer Group
內部的consumer
並行度完全依賴於被消費的分割槽數量。綜上所述,通常情況下,在一個Kafka
叢集中,partition
的數量越多,意味著可以到達的吞吐量越大。
我們可以粗略地通過吞吐量來計算kafka
叢集的分割槽數量。假設對於單個partition
,producer
端的可達吞吐量為p
,Consumer
端的可達吞吐量為c
,期望的目標吞吐量為t,那麼叢集所需要的partition
數量至少為max(t/p,t/c)
。在producer
端,單個分割槽的吞吐量大小會受到批量大小、資料壓縮方法、 確認型別(同步/非同步)、複製因子等配置引數的影響。經過測試,在producer
端,單個partition
的吞吐量通常是在10MB/s
左右。在consumer
端,單個partition
的吞吐量依賴於consumer
端每個訊息的應用邏輯處理速度。因此,我們需要對consumer
端的吞吐量進行測量。
雖然隨著時間的推移,我們能夠對分割槽的數量進行新增,但是對於基於Key
來生成的這一類訊息需要我們重點關注。當producer
向kafka寫入基於key的訊息時,kafka
通過key
的hash
值來確定訊息需要寫入哪個具體的分割槽。通過這樣的方案,kafka
能夠確保相同key
值的資料可以寫入同一個partition
。kafka的這一能力對於一部分應用是極為重要的,例如對於同一個key的所有訊息,consumer
需要按訊息的順序進行有序消費。如果partition
的數量發生改變,那麼上面的有序性保證將不復存在。為了避免上述情況發生,通常的解決辦法是多分配一些分割槽,以滿足未來的需求。通常情況下,我們需要根據未來1到2年的目標吞吐量來設計kafka
的分割槽數量。
一開始,我們可以基於當前的業務吞吐量為kafka
叢集分配較小的broker
數量,隨著時間的推移,我們可以向叢集中增加更多的broker
,然後線上方式將適當比例的partition
轉移到新增加的broker
中去。通過這樣的方法,我們可以在滿足各種應用場景(包括基於key
訊息的場景)的情況下,保持業務吞吐量的擴充套件性。
在設計分割槽數時,除了吞吐量,還有一些其他因素值得考慮。正如我們後面即將看到的,對於一些應用場景,叢集擁有過的分割槽將會帶來負面的影響。
越多的分割槽需要開啟更多地檔案控制程式碼
在kafka
的broker
中,每個分割槽都會對照著檔案系統的一個目錄。在kafka
的資料日誌檔案目錄中,每個日誌資料段都會分配兩個檔案,一個索引檔案和一個資料檔案。當前版本的kafka
,每個broker
會為每個日誌段檔案開啟一個index
檔案控制程式碼和一個資料檔案控制程式碼。因此,隨著partition
的增多,需要底層作業系統配置更高的檔案控制程式碼數量限制。這更多的是一個配置問題。我們曾經見到過,在生產環境Kafka
叢集中,每個broker
開啟的檔案控制程式碼數量超過30,000
。
更多地分割槽會導致更高的不可用性
Kafka
通過多副本複製技術,實現kafka叢集的高可用和穩定性。每個partition
都會有多個資料副本,每個副本分別存在於不同的broker
。所有的資料副本中,有一個資料副本為Leader
,其他的資料副本為follower
。在kafka叢集內部,所有的資料副本皆採用自動化的方式進行管理,並且確保所有的資料副本的資料皆保持同步狀態。不論是producer
端還是consumer
端發往partition
的請求,皆通過leader
資料副本所在的broker
進行處理。當broker
發生故障時,對於leader
資料副本在該broker
的所有partition
將會變得暫時不可用。Kafka
將會自動在其他資料副本中選擇出一個leader
,用於接收客戶端的請求。這個過程由kafka controller
節點broker
自動完成,主要是從Zookeeper
讀取和修改受影響partition
的一些後設資料資訊。在當前的kafka版本實現中,對於zookeeper
的所有操作都是由kafka controller
來完成的(serially
的方式)。
在通常情況下,當一個broker
有計劃地停止服務時,那麼controller
會在服務停止之前,將該broker
上的所有leader
一個個地移走。由於單個leader
的移動時間大約只需要花費幾毫秒,因此從客戶層面看,有計劃的服務停機只會導致系統在很小時間視窗中不可用。(注:在有計劃地停機時,系統每一個時間視窗只會轉移一個leader
,其他leader
皆處於可用狀態。)
然而,當broker
非計劃地停止服務時(例如,kill -9
方式),系統的不可用時間視窗將會與受影響的partition
數量有關。假如,一個2節點的kafka
叢集中存在2000個partition
,每個partition
擁有2個資料副本。當其中一個broker
非計劃地當機,所有1000個partition
同時變得不可用。假設每一個partition
恢復時間是5ms,那麼1000個partition
的恢復時間將會花費5秒鐘。因此,在這種情況下,使用者將會觀察到系統存在5秒鐘的不可用時間視窗。
更不幸的情況發生在當機的broker
恰好是controller
節點時。在這種情況下,新leader
節點的選舉過程在controller
節點恢復到新的broker
之前不會啟動。Controller
節點的錯誤恢復將會自動地進行,但是新的controller
節點需要從zookeeper
中讀取每一個partition
的後設資料資訊用於初始化資料。例如,假設一個kafka
叢集存在10,000個partition
,從zookeeper
中恢復後設資料時每個partition
大約花費2ms,則controller
的恢復將會增加約20秒的不可用時間視窗。
通常情況下,非計劃的當機事件發生的情況是很少的。如果系統可用性無法容忍這些少數情況的場景,我們最好是將每個broker
的partition
數量限制在2,000到4,000,每個kafka叢集中partition
的數量限制在10,000以內。
越多的分割槽可能增加端對端的延遲
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
放到一個broker
節點和放到10個broker
節點,他們之間的延遲是存在差異的。在10個broker
節點的叢集中,每個broker
節點平均需要處理100
個分割槽的資料複製。此時,端對端的延遲將會從原來的數十毫秒變為僅僅需要幾毫秒。
根據經驗,如果你十分關心訊息延遲問題,限制每個broker
節點的partition
數量是一個很好的主意:對於b
個broker
節點和複製因子為r
的kafka
叢集,整個kafka
叢集的partition
數量最好不超過100*b*r
個,即單個partition
的leader
數量不超過100
.
越多的partition
意味著需要客戶端需要更多的記憶體
在最新發布的0.8.2
版本的kafka
中,我們開發了一個更加高效的Java producer
。新版producer
擁有一個比較好的特徵,他允許使用者為待接入訊息儲存空間設定記憶體大小上限。在內部實現層面,producer
按照每一個partition
來快取訊息。在資料積累到一定大小或者足夠的時間時,積累的訊息將會從快取中移除併發往broker
節點。
如果partition
的數量增加,訊息將會在producer
端按更多的partition
進行積累。眾多的partition
所消耗的記憶體彙集起來,有可能會超過設定的內容大小限制。當這種情況發生時,producer
必須通過訊息堵塞或者丟失一些新訊息的方式解決上述問題,但是這兩種做法都不理想。為了避免這種情況發生,我們必須重新將produder
的記憶體設定得更大一些。
根據經驗,為了達到較好的吞吐量,我們必須在producer
端為每個分割槽分配至少幾十KB
的記憶體,並且在分割槽數量顯著增加時調整可以使用的記憶體數量。
類似的事情對於consumer
端依然有效。Consumer
端每次從kafka
按每個分割槽取出一批訊息進行消費。消費的分割槽數越多,需要的記憶體數量越大。儘管如此,上述方式主要運用於非實時的應用場景。
總結
通常情況下,kafka
叢集中越多的partition
會帶來越高的吞吐量。但是,我們必須意識到叢集的partition
總量過大或者單個broker
節點partition
過多,都會對系統的可用性和訊息延遲帶來潛在的影響。未來,我們計劃對這些限制進行一些改進,讓kafka
在分割槽數量方面變得更加可擴充套件。
相關文章
- 為Hadoop叢集選擇合適的硬體配置Hadoop
- 如何選擇一個Kafka叢集中的主題分割槽的數量Kafka
- 如何為Kafka叢集確定合適的分割槽數以及分割槽數過多帶來的弊端Kafka
- 如何為DMAIC選擇合適的專案AI
- 如何選擇合適的 BI 工具?
- 如何快速為網站選擇合適的SSL證書網站
- 如何選擇合適的建站系統
- 為MySQL選擇合適的備份方式MySql
- 如何為專案選擇合適的專案管理軟體專案管理
- 如何選擇合適的NoSQL資料庫SQL資料庫
- 如何選擇最好最適合你的MacBookMac
- 伺服器如何選擇合適的配置伺服器
- 如何選擇合適自己的伺服器伺服器
- 如何選擇合適的美國伺服器?伺服器
- 如何選擇適合自己的程式語言
- 如何選擇合適的MySQL儲存引擎MySql儲存引擎
- 巨型專案如何選擇合適的框架?框架
- 為應用選擇合適的同步高速SRAM
- 如何選擇適合RCD負載箱負載
- 如何為您選擇合適的製造執行系統(MES)?
- 如何選擇合適的SSL證書型別型別
- 如何選擇適合你的程式碼風格?
- 如何正確選擇適合的CRM系統?
- 伺服器如何選擇合適的IO模型伺服器模型
- GitHub如何選擇合適的license(許可證)Github
- 團隊如何選擇合適的Git分支策略?Git
- 如何選擇最適合自己的伺服器伺服器
- web開發|如何選擇合適的webui框架WebUI框架
- 如何選擇合適的Linux發行版Linux
- 如何使用kafka增加topic的備份數量,讓業務更上一層樓Kafka
- Kafka詳解二、如何配置Kafka叢集Kafka
- Zookeeper叢集 + Kafka叢集Kafka
- 如何選擇合適的自動化測試工具?
- java培訓機構如何選擇適合自己的Java
- 如何選擇適合自己企業的MES系統
- 如何選擇最適合您的代理提供商?
- 如何選擇適合自己的solidworks軟體版本Solid
- 如何選擇適合管理銷售的CRM系統?