如何爲Kafka集羣選擇合適的Partitions數量

這是許多kafka使用者常常會問到的一個問題。本文的目的是介紹與本問題相關的一些重要決策因素,並提供一些簡單的計算公式。php

文章目錄html

  越多的分區能夠提供更高的吞吐量

  首先咱們須要明白如下事實:在kafka中,單個patition是kafka並行操做的最小單元。在producer和broker端,向每個分區寫入數據是能夠徹底並行化的,此時,能夠經過加大硬件資源的利用率來提高系統的吞吐量,例如對數據進行壓縮。在consumer段,kafka只容許單個partition的數據被一個consumer線程消費。所以,在consumer端,每個Consumer Group內部的consumer並行度徹底依賴於被消費的分區數量。綜上所述,一般狀況下,在一個Kafka集羣中,partition的數量越多,意味着能夠到達的吞吐量越大。url

  咱們能夠粗略地經過吞吐量來計算kafka集羣的分區數量。假設對於單個partition,producer端的可達吞吐量爲p,Consumer端的可達吞吐量爲c,指望的目標吞吐量爲t,那麼集羣所須要的partition數量至少爲max(t/p,t/c)。在producer端,單個分區的吞吐量大小會受到批量大小、數據壓縮方法、 確認類型(同步/異步)、複製因子等配置參數的影響。通過測試,在producer端,單個partition的吞吐量一般是在10MB/s左右。在consumer端,單個partition的吞吐量依賴於consumer端每一個消息的應用邏輯處理速度。所以,咱們須要對consumer端的吞吐量進行測量。spa

  雖然隨着時間的推移,咱們可以對分區的數量進行添加,可是對於基於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在分區數量方面變得更加可擴展。

英文原文:http://www.confluent.io/blog/how-to-choose-the-number-of-topicspartitions-in-a-kafka-cluster/

相關文章
相關標籤/搜索