發表日期 3/3/2022, 8:10:05 AM
作者 | Abdul Qadeer
譯者 | 平川
策劃 | Tina
在 PayPal,我們最近開始試水 Kubernetes。我們大部分的工作負載都運行在 Apache Mesos 上,而作為遷移的一部分,我們需要從性能方麵瞭解下運行 Kubernetes 集群以及 PayPal 特有的控製平麵。其中最主要的是瞭解平台的可擴展性,以及通過調整集群找齣可以改進的地方。
本文最初發布於 PayPal 技術博客。
在 PayPal,我們最近開始試水 Kubernetes。我們大部分的工作負載都運行在 Apache Mesos 上,而作為遷移的一部分,我們需要從性能方麵瞭解下運行 Kubernetes 集群以及 PayPal 特有的控製平麵。其中最主要的是瞭解平台的可擴展性,以及通過調整集群找齣可以改進的地方。
與 Apache Mesos 不同的是,前者無需任何修改即可擴展到 10,000 個節點,而擴展 Kubernetes 則非常具有挑戰性。Kubernetes 的可擴展性不僅僅體現在節點和 Pod 的數量上,還有其他多個方麵,如創建的資源數量、每個 Pod 的容器數量、服務總數和 Pod 部署的吞吐量。本文描述瞭我們在擴展過程中遇到的一些挑戰,以及我們如何解決這些問題。
集群拓撲
我們的生産環境中有各種不同規模的集群,包含數韆個節點。我們的設置包括三個主節點和一個外部的三節點 etcd 集群,所有這些都運行在榖歌雲平台(GCP)上。控製平麵前麵有一個負載平衡器,所有數據節點都與控製平麵屬於相同的區域。
工作負載
為瞭進行性能測試,我們使用瞭一個開源的工作負載生成器 k-bench,並針對我們的場景做瞭修改。我們使用的資源對象是簡單的 Pod 和部署。我們按不同的批次大小和部署間隔時間,分批次連續對它們進行部署。
擴 展
開始時,Pod 和節點數量都比較少。通過壓力測試,我們發現可以改進的地方,並繼續擴大集群的規模,因為我們觀察到性能有所改善。每個工作節點有四個 CPU 內核,最多可容納 40 個 Pod。我們擴展到大約 4100 個節點。用於基準測試的應用程序是一個無狀態的服務,運行在 100 個服務質量(QoS)有保證的毫核(millicores )上。
我們從 1000 個節點、2000 個 Pod 開始,接著是 16000 個 Pod,然後是 32000 個 Pod。之後,我們躍升到 4100 個節點、15 萬個 Pod,接著是 20 萬個 Pod。我們不得不增加每個節點的核數,以容納更多的 Pod。
API 服務器
事實證明,API 服務器是一個瓶頸,有幾個到 API 服務器的連接返迴 504 網關超時,此外還有本地客戶端限流(指數退避)。這些問題在擴展過程中 呈 指數級 增長:
I0504 17:54:55.731559 1 request.go:655] Throttling request took 1.005397106s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-14/Pods..
I0504 17:55:05.741655 1 request.go:655] Throttling request took 7.38390786s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-13/Pods..
I0504 17:55:15.749891 1 request.go:655] Throttling request took 13.522138087s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-13/Pods..
I0504 17:55:25.759662 1 request.go:655] Throttling request took 19.202229311s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-20/Pods..
I0504 17:55:35.760088 1 request.go:655] Throttling request took 25.409325008s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-13/Pods..
I0504 17:55:45.769922 1 request.go:655] Throttling request took 31.613720059s, request: POST:https://:443/api/v1/namespaces/kbench-deployment-namespace-6/Pods..
API 服務器上限製速率的隊列的大小是通過 max-mutating-requests-inflight 和 max-requests-inflight 更新的。1.20 版本中引入的優先級和公平性特性測試版,就是在 API 服務器上這兩個標記的控製下將隊列的總大小在不同的隊列類彆之間進行劃分。例如,群首選舉請求的優先級比 Pod 請求高。在每個優先級中,都有可配置隊列的公平性。未來還可以通過 PriorityLevelConfiguration&FlowSchema API 對象做進一步調優。
控製器管理器
控製器管理器負責為副本集、命名空間等本地資源以及數量眾多的部署(由副本集管理)提供控製器。控製器管理器與 API 服務器同步其狀態的速度是有限的。有多個調節器用於調整這一行為:
kube-api-qps―― 控製器管理器在一秒鍾內可以嚮 API 服務器進行查詢的次數。
kube-api-burst―― 控製器管理器突發流量峰值,是kube-api-qps之上另一個並發調用數。
concurrent-deployment-syncs―― 部署、復製集等對象同步調用的並發性。
調度器
當作為一個獨立的組件單獨測試時,調度器可以支持每秒 1000 個 Pod 的高吞吐率。然而,在將調度器部署到一個在綫集群中時,我們注意到,實際的吞吐量有所降低。 etcd 實例速度慢導緻調度器的綁定延遲增加 ,使得待處理隊列的大小增加到數韆個 Pod 的程度。我們的想法是在測試運行期間將這個數值保持在 100 以下,因為數量比較大的話會影響 Pod 的啓動延遲。此外,我們最後還調整瞭群首選舉參數,以應對短暫的網絡分區或網絡擁堵引發的虛假重啓。
etcd
etcd 是 Kubernetes 集群中最關鍵的一部分。這一點從 etcd 在整個集群中引發的、以不同方式錶現齣來的大量問題可以看齣來。經過非常仔細的研究,我們纔找到根本原因,並擴展 etcd 以匹配我們預期的規模。
在擴展過程中,許多 Raft proposal 開始失敗
通過調查分析,我們發現,GCP 將 PD-SSD 磁盤的吞吐量限製在每秒 100MB 左右(如下圖所示),我們的磁盤大小為 100G。GCP 沒有提供增加吞吐量限製的方法――它隻隨著磁盤的大小增加。盡管 etcd 節點隻需要不到 10G 的空間,我們首先嘗試瞭 1TB PD-SSD。然而,當所有 4k 個節點同時加入 Kubernetes 控製平麵時,磁盤再大也會成為一個 瓶頸 。我們決定使用本地 SSD,它的吞吐量非常高,代價是在齣現故障時丟失數據的幾率略高,因為它不是持久化的。
在遷移到本地 SSD 後,我們並沒有看到最快的 SSD 帶來瞭預期的性能。我們用 FIO 直接在磁盤上做瞭一些基準測試,數值在意料之中。但是,對於所有成員的寫入並發,etcd 基準測試講述瞭一個不同的故事:
Plain TextLOCAL SSDSummary: Total: 8.1841 secs. Slowest: 0.5171 secs. Fastest: 0.0332 secs. Average: 0.0815 secs. Stddev: 0.0259 secs.Requests/sec: 12218.8374
PD SSD
Summary:
Total: 4.6773 secs.
Slowest: 0.3412 secs.
Fastest: 0.0249 secs.
Average: 0.0464 secs.
Stddev: 0.0187 secs.
Requests/sec: 21379.7235
本地 SSD 的錶現更差!經過深入調查,這是由 ext4 文件係統的寫屏障緩存提交導緻的。由於 etcd 使用寫前日誌,並在每次提交到 Raft 日誌時調用 fsync,所以可以禁用寫屏障。此外,我們在文件係統級和應用程序級有 DB 備份作業,用於 DR。在這樣修改之後,使用本地 SSD 的數值提高到瞭與 PD-SSD 相當的程度:
Plain TextLOCAL SSDSummary: Total: 4.1823 secs. Slowest: 0.2182 secs. Fastest: 0.0266 secs. Average: 0.0416 secs. Stddev: 0.0153 secs. Requests/sec: 23910.3658
這一改進的效果在 etcd 的 WAL 同步持續時間和後端提交延遲上體現瞭齣來,如下圖所示,在 15:55 左右這個時間點上,WAL 同步持續時間和後端提交延遲降低瞭 90% 以上
etcd 中默認的 MVCC 數據庫大小為 2GB。在 DB 空間不足的告警被觸發時,這個大小最大會增加到 8GB。由於該數據庫的 利用率約為 60% ,所以我們能夠擴展到 20 萬個無狀態 Pod。
經過上述這些優化,在預期的規模下,集群更加穩定瞭,然而,在 API 延遲方麵,我們的 SLI 還差很多。
etcd 服務器還會偶爾重啓,僅一次重啓就會破壞基準測試結果,尤其是 P99 值。仔細觀察發現,v1.20 版的 etcd YAML 中有一個存活探針 Bug。為瞭解決這個問題,我們采用瞭一個變通辦法,即增加失敗閾值的計數。
在用盡所有方法對 etcd 進行瞭垂直擴展之後,主要是在資源方麵(CPU、內存、磁盤),我們發現,etcd 的性能受到範圍查詢的影響。當範圍查詢很多時,etcd 的錶現並不好,對 Raft 日誌的寫入也受到影響,增加瞭集群的延遲。以下是一次測試運行中影響性能的每個 Kubernetes 資源的範圍查詢的數量:
Plain Textetcd$ sudo grep -ir "events" 0.log.20210525-035918 | wc -l130830etcd$ sudo grep -ir "Pods" 0.log.20210525-035918 | wc -l107737etcd$ sudo grep -ir "configmap" 0.log.20210525-035918 | wc -l86274etcd$ sudo grep -ir "deployments" 0.log.20210525-035918 | wc -l6755etcd$ sudo grep -ir "leases" 0.log.20210525-035918 | wc -l4853etcd$ sudo grep -ir "nodes" 0.log.20210525-035918 | wc -l
由於這些查詢很耗時,etcd 的後端延遲受到瞭很大的影響。在事件資源上對 etcd 服務器進行分片管理後,我們看到,在 Pod 高度競爭的情況下,集群的穩定性有所提高。將來,還可以進一步在 Pod 資源上對 etcd 集群進行分片。配置 API 服務器聯係相關的 etcd 以與分片的資源進行交互很容易。
結 果
在對 Kubernetes 的各種組件做完優化和調整後,我們觀察到,延遲有大幅改善。下圖展示瞭隨著時間的推移,為滿足 SLO 而實現的性能提升。其中,工作負載是 150k 個 Pod,每個部署 250 個副本,10 個並發工作進程。隻要 Pod 啓動的 P99 延遲在 5 秒之內,按照 Kubernetes SLO,我們就算是很好瞭
下圖顯示瞭當集群有 20 萬個 Pod 時,API 調用延遲完全符閤 SLO。
我們還實現瞭 20 萬個 Pod P99 啓動延遲為 5 秒左右,而 Pod 部署速率遠遠高於 K8s 針對 5k 節點測試時所聲稱的 3000 個 Pod/ 分鍾。
總 結
Kubernetes 是一個復雜的係統,必須深入瞭解控製平麵,纔能知道如何擴展每個組件。通過這次操練,我們學到瞭很多東西,並將繼續優化我們的集群。
查看英文原文:
https://medium.com/paypal-tech/scaling-kubernetes-to-over-4k-nodes-and-200k-pods-29988fad6ed?