1. 程式人生 > >【譯】Apache Kafka支援單叢集20萬分區

【譯】Apache Kafka支援單叢集20萬分區

  之前網上關於確定Kafka分割槽數的部落格多多少少都源自於饒軍大神的文章,如今他帶來了這方面的第二篇文章,特此翻譯一下,記錄一下其中的要點。

  原貼地址: https://www.confluent.io/blog/apache-kafka-supports-200k-partitions-per-cluster


 

  Kafka中topic可以設定多個分割槽,而分割槽是最小的並行度單位。通常而言,分割槽數越多吞吐量也越高。但是依然有很多因素制約了一個Kafka叢集所能支援的最大分割槽數。我現在高興地宣佈Kafka 1.1.0版本在這方面取得了重大的改進。目前生產環境中單Kafka叢集支援的分割槽上限得到了極大的提升。

  為了便於理解這個改進是如何實現的,我們重溫一下分割槽leader和controller的基本概念。首先,每個分割槽都可以配置多個副本用於實現高可用性以及永續性。其中的一個副本被指定為leader而所有client只與leader進行互動;其次,cluster中的某個broker被指定為controller來管理整個叢集。若broker掛掉,controller負責為該broker上所有分割槽選舉leader。

  預設情況下關閉Kafka broker執行的是一個受控關閉操作(下稱controlled shutdown)。Controlled shutdown對client的影響是最小的。一個典型的controlled shutdown分為以下幾步:1. 傳送SIGTERM訊號給待關閉的broker;2. Broker傳送請求給controller表明自己要正常關閉;3. Controller變更該broker上所有分割槽的leader並將這部分資料儲存回Zookeeper;4. Controller傳送新的leader資訊給其他broker;5. Controller傳送響應給關閉中的broker表明操作成功,於是broker成功關閉。此時,client端不受任何影響因為新leader已經轉移到其他broker上。下面的兩張圖描述了這個過程,注意到圖中(4)和(5)步是可以並行執行的:

       

上圖中步驟(1)發起broker關閉;步驟(2)傳送controlled shutdown請求給controller;步驟(3)中controller寫入新leader到Zookeeper;步驟(4)controller傳送新leader資訊到其他broker;步驟(5)controller傳送成功資訊給關閉中的broker

   在Kafka 1.1.0之前,一旦發起controlled shutdown,controller每次只能為一個分割槽選舉leader。對於每個分割槽而言,controller順序執行:選擇新leader、同步寫leader資訊回Zookeeper以及同步leader資訊給其他broker等操作。這種設計是低效率的:首先,同步寫入Zookeeper就有很高的延時,從而整體拖慢controller shudown時間;其次,每次處理一個分割槽的做法導致需要給其他broker傳送很多次請求,即使這些請求本身攜帶的資料量是很小的,從而最終導致對新leader的處理時間被極大地拉長。

  Kafka 1.1.0為controlled shutdown引入了多個方面的效能提升。第一個提升就是使用非同步API來替代了之前的同步寫入Zookeeper。在controlled shutdown過程中,Kafka不再是每次寫入一個leader資訊,等待其完成然後再寫入下一個。相反地,controller使用非同步API一次性地提交多個分割槽的leader到Zookeeper上,然後統一等待其執行完畢。這就等於在Kafka與Zookeeper之間構建了一種管道式請求處理流程,從而減少了整體的延時。第二個提升則是將於新leader的互動操作批量化。與其每次為一個分割槽傳送RPC請求,controller使用單個RPC請求一次性地攜帶所有受影響分割槽的leader資訊。

  同時,Kafka對於controller failover的時間也做了優化。當controller掛掉後,Kafka叢集自動檢測controller失敗並選擇其他broker作為新的controller。在開啟controller工作之前,新選出的controller必須要從Zookeeper中載入所有分割槽的狀態資訊到記憶體中。如果controller直接崩潰的話,分割槽不可用的時間視窗將等同於Zookeeper會話超時時間加上controller狀態載入時間,所以降低載入時間能夠有效地幫助我們改善Kafka可用性。在1.1.0之前,載入操作使用的也是同步Zookeeper API。在1.1.0中被替換成了非同步API。

  社群對controlled shutdown時間和載入時間都做了測試。每個測試都使用了5節點Zookeeper的叢集。在測試controlled shutdown時,社群搭建了一個5節點broker的Kafka叢集併為該叢集建立了25000個單分割槽的topic,每個topic都是雙副本,故每個broker上平均有10000個分割槽。之後測試controlled shutdown,測試結果如下:

  提升的很大一部分來自於修復了打日誌(logging)的開銷:之前在每個分割槽leader變更時都會記錄叢集中所有分割槽的資料——這實際上是沒必要的。通過修復了這個logging的bug,controller shutdown從6.5分鐘被壓縮到30秒,而採用非同步API更進一步地將其拉低到3秒。這些提升都極大地縮短了Kafka叢集重啟恢復的時間。

  在第二項測試中,社群同樣搭建了一個5節點叢集,只不過這次建立了2000個配置有50分割槽的topic,單副本——故總數是1000000個分割槽。當測試controller狀態載入時間時發現比1.0.0有了100%的提升(1.0.0耗時28秒,1.1.0耗時14秒)。

  有了這些提升,Kafka單叢集能夠支援多少分割槽呢?確切的數字自然依賴於諸如可容忍的不可用視窗時間、Zookeeper延時、broker儲存型別等因素。根據經驗法則我們評估單臺broker能夠支撐的分割槽數可達4000個,而單叢集能夠支撐200000個分割槽。當然後者主要受限於叢集對controller崩潰這種不常見情形的容忍度,另外其他影響分割槽數的因素也要考慮進來。

  1.1.0所做的改進僅僅是提升Kafka高擴充套件性的一小步。事實上社群在1.1.0版本還嘗試了更多的分割槽並改進了它們的延時表現。後面可能會在另一篇文章中給出具體的說明。在未來,Kafka社群計劃實現單叢集支撐百萬級分割槽的構想,所以,敬請期待~~