使用開源元件構建自動運維Kafka叢集 - Slack

banq發表於2022-06-06

Slack團隊使用 Cruise Control、Kafka Manager、Chef 和 Terraform 等開源元件大規模執行自我修復的 Kafka 叢集。此外,使用標準 SRE 原則和適當的工具(如 Kafka Manager 和 Kafka offset exporter),可以使 Kafka 變得可靠、自助服務和自動駕駛。

在過去的幾年裡,Slack 一直在成功執行這種架構。展望未來,Kafka 將在 Slack 中扮演更重要的角色,因為它是新的變更資料捕獲 (CDC) 專案的一部分。新的 CDC 功能將支援 Slack 許可權服務的快取需求,該服務用於授權 Slack 中的操作,還將實現對我們的資料倉儲的近實時更新。為此,我們在 Slack 組建了一個新的資料流團隊來處理所有當前和未來的 Kafka 用例。新的資料流團隊將維護和支援 Slack 的所有 Kafka 叢集。該團隊還將負責構建與 Kafka 相關的標準化庫和工具,並將致力於進一步改進當前的 Kafka 操作和效率。

什麼是自驅動 Kafka 叢集?
Kafka 是一款出色的軟體,可在 Slack 的數百個節點上執行。但是,如果您曾經嘗試過部署或管理 Kafka,您就會知道這並非易事。經常遭遇緩慢問題,有時是當機的代理或容量管理問題。

自動化 Kafka 操作的目標是消除日常管理 Kafka 的運維開銷。

為此,我們為 Kafka 叢集確定了一些常見的運維操作任務,包括:

  • 例行的 Kafka 管理操作,例如建立主題、更改分割槽計數和將分割槽重新分配給代理
  • 容量規劃操作,例如向叢集新增/刪除代理
  • 更換代理或部署新版本軟體等運營問題
  • 診斷 Kafka 叢集中問題的隨叫隨到的負擔
  • 客戶支援解釋 Kafka 消費者是否跟上

因此,當我們遷移到新版本的 Kafka 叢集時,我們決定將其操作方面自動化,或者使其成為自助服務。

Kafka 2專案
我們透過使用2.0.1版本的Kafka,統一了我們的努力,使Kafka更加自動化。我們的Kafka設定由以下部分組成:

構建、釋出、配置和部署、Chef和Terraform

我們使用Chef來管理基礎作業系統,在主機上部署和配置Kafka軟體。我們的每個Kafka叢集都在不同的角色下執行,有其自定義的配置,但它們都共享相同的底層配方。我們有一個Terraform模組,為AWS中的這個Chef角色建立一個ASG。ASG會自動管理節點的配置和刪除。

舊的Kafka部署主要是透過部署Debian Kafka包來管理。然而,我們發現部署預先建立的軟體包是很痛苦的,因為供應並不總是可靠的。此外,由於我們無論如何都要覆蓋預設配置,所以我們的Chef配方很複雜。為了解決這些問題,我們建立了一個Kafka repo的內部分叉,並設定了我們的CI/CD管道來構建和釋出靜態二進位制檔案到S3。然後,我們的Chef配方將從S3中提取二進位制檔案進行部署,這使得供應非常可重複。

傳統上,Apache Zookeeper 3.4叢集是手動配置的,因為我們沒有一個自動化的方法來確保每個Zookeeper節點都有唯一的ID,而且如果沒有叢集範圍內的重新啟動,就無法分配新的ID。手動配置Zookeeper節點不僅繁瑣(我們被呼喚常規節點故障),而且容易出錯,因為我們會意外地在同一AWS可用區啟動多個Zookeeper節點,增加我們的爆炸半徑。為了減少繁瑣和錯誤,我們透過升級到Zookeeper 3.6來自動化這一過程,在更換經紀商時不需要在整個叢集範圍內重新啟動。然後,在Zookeeper節點加入叢集之前,我們透過Consul KV將唯一的ID分配給Zookeeper節點的過程自動化。有了這兩個變化,我們就能透過ASG使用Terraform配置我們的Zookeeper叢集了。

調整Kafka叢集的穩定性
雖然這種設定有助於自動解決配置主機的痛點,但我們仍然需要管理叢集操作,比如將分割槽遷移到新的broker上,並重新平衡broker的負載。此外,這樣的叢集管理操作對我們的客戶造成了干擾,導致他們被呼喚或錯過他們的SLO。

經過一些分析,我們發現Kafka叢集中的熱點導致了不穩定。而這些熱點是由幾個不同的問題造成的。

我們有幾百個Kafka主題,它們被分配到我們的叢集中。我們注意到,每個主題都有一個基於負載的不同分割槽數。在常規操作的過程中,一些經紀商會比其他經紀商執行得更熱。這些熱點又會在叢集管理操作中加劇,比如新增和刪除broker經紀人,從而導致我們的Kafka消費者在消費時出現延遲。

為了解決熱點問題,我們希望均勻地利用叢集中的所有broker經紀人。首先,為了抹平寫的熱點,我們把所有分割槽的數量改為經紀人數量的倍數。我們還透過在所有節點上挑選消費者數量來平滑讀取熱點。這一起平滑了叢集上的讀寫率。 只要所有這些分割槽都均勻地分佈在叢集周圍,我們就能在整個叢集中獲得可靠的利用率。此外,當我們擴大經紀人或消費者的規模時,我們將更新主題的分割槽數量,使分割槽數量仍然是經紀人數量的倍數,以確保均勻的利用率。

Kafka叢集出現熱點的另一個原因是在分割槽重新平衡事件中消耗的複製頻寬。我們發現,大部分的資源被複制頻寬飢餓的生產者或消費者所消耗,尤其是在高峰期。因此,我們限制了叢集所能使用的複製頻寬。然而,限制複製頻寬導致我們的叢集管理操作變得相當緩慢。我們還修改了我們的操作,每次只移動少量的分割槽。這使得我們可以持續地進行大量的小改動。

儘管做了這些努力,Kafka叢集還是會因為部分故障而出現不平衡的情況。為了使這些變化自動化,我們使用了LinkedIn構建的優秀的Cruise Control自動化套件,使叢集的再平衡操作自動化,並確保叢集中所有節點的平均利用率。總的來說,這些調整導致了叢集的穩定執行。

混亂工程 
由於從現有的叢集切入是一個很大的變化,我們在prod中使用暗流量測試這個新叢集時,進行了一些混沌實驗。

我們的測試涉及到叢集中各種資源在負載下的飽和。此外,我們能夠在受控條件下終止經紀人,這有助於我們更好地瞭解我們經紀人的失敗模式及其對生產者和消費者的影響。

在這些測試中,我們發現,我們的叢集恢復操作主要受限於主機每秒傳送的資料包數量。為了支援更快的恢復,我們在這些主機上啟用了巨量幀。我們的Kafka例項在Slack的基礎設施艦隊中擁有一些最高的每秒包數利用率。

此外,這也幫助我們在使用Go Sarama庫的消費者中發現了一些邊緣案例的錯誤。在某些情況下,我們將這些消費者遷移到Confluent Go消費者,這也幫助我們在不同的語言中實現客戶端配置的標準化。在無法升級消費者的情況下,我們新增了適當的變通方法和警報來監控這些用例。

在這些測試中,我們還意識到,Zookeeper的問題很快就會演變成更大的Kafka問題。因此,儘管成本略高,我們還是為每個Kafka叢集使用了一個單獨的Zookeeper叢集,以減少Zookeeper故障的爆炸半徑。

混沌測試也幫助我們瞭解在真正的故障中會出現的操作問題,並幫助我們對叢集進行更多的調整。

自我服務的Kafka叢集 
有很多情況下,我們的消費者團隊會主動聯絡我們,詢問或要求增加或刪除叢集的容量。其中一組問題是關於常規的運營問題,如容量規劃,另一組問題是瞭解他們管道的健康狀況。

此外,使用CLI工具來了解Kafka的情況也很乏味。因此,我們部署了kafka管理器,讓每個人都能看到Kafka叢集的後設資料,如經紀人和主題列表。Kafka管理器還幫助我們簡化了常規操作,如建立新主題和增加主題的分割槽數量。

為了提供對Kafka消費者健康狀況的操作可見性,我們部署了一個kafka偏移量匯出器的分叉,將消費者偏移量資訊匯出為Prometheus指標。在這些資料的基礎上,我們建立了一個儀表盤,向消費者實時提供每個主題、每個消費者和彙總的消費指標。

為了減少知識的孤島,我們將各種執行簿標準化為一個單一的單頁執行簿。這有助於將所有的Kafka知識彙總到一個地方。此外,我們還將多個Kafka儀表盤整合為一個單一的全球儀表盤,用於我們所有的Kafka叢集。

這些自助工具一起幫助我們的客戶更好地瞭解資料,同時減少了團隊的運營開銷。這些工具還幫助我們改善了安全狀況,最大限度地減少了SSH進入Kafka經紀商的需要。

升級Kafka叢集
為了升級Kafka叢集,我們決定不做原地叢集升級,原因有幾個。我們沒有信心確保在升級視窗期間的零停機時間,尤其是在同時升級幾個版本的時候。 此外,我們沒有辦法驗證新的叢集是否有問題,特別是在改變底層硬體型別時。

為了解決這些問題,我們制定了一個新的升級政策,在這個政策下,我們會切換到新的叢集。切換過程如下。

  • 啟動一個新的叢集
  • 在新叢集上使用暗流量執行任何驗證測試
  • 停止向舊叢集提供資料
  • 開始向新叢集生產資料
  • 在保留視窗到期後關閉舊叢集

雖然這個策略有協調切割消費者的缺點,但它是一個標準的操作程式,也適用於其他場景,如跨叢集移動主題和測試新的EC2例項型別。

拆分主Kafka叢集
在我們投入時間讓Kafka自我維持和可靠之後,我們為自己贏得了寶貴的時間來開發其他具有高度影響力的功能,比如追蹤。然而,即使我們投入了這麼多的工作,還是會有一個時間點,那就是一個系統已經達到了需要重新審視假設和能力的程度。

我們在2021年初接近了這個點。我們由90個經紀人broker組成的單一叢集在網路吞吐量上達到了臨界點,上限為40,000 pps。網路飽和導致下游管道落後,因為Kafka在正常工作負荷下很難跟上消費者,更不用說處理巨大的流量高峰了。我們依賴日誌管道來除錯問題的開發人員每天都會受到Kafka網路飽和的影響。

為了減輕主Kafka叢集的負載,我們利用我們的工具和自動化,將大型主題拆分到他們自己的更小、更高效能的叢集中(從舊的d2例項升級到現代的nitro-en例項)。比較兩個叢集之間的類似工作負載,較新的叢集能夠在20個經紀人上實現類似的效能(每1,000 pps),從而使效率大約提高2.5倍。

在將三個最大的主題移出主叢集后,我們看到叢集上的情況立即得到緩解。

 

相關文章