有3億用戶的美版「小紅書」Pinterest如何平穩擴展K8s?

有3億用戶的美版「小紅書」Pinterest如何平穩擴展K8s?

Anson Qian 架構頭條

rnetes平台的用戶反饋都很正面。根據我們的調查,在用戶心中排行前三

作者 | Anson Qian

譯者 | 馬可薇

策劃 | 萬佳

作為美國知名的圖片社交網站,Pinterest 坐擁 3 億用戶,類似於中國小紅書。2017 年,Pinterest 走上 Kubernetes 之旅。但隨著用戶激增,負載飆升,其 K8s 平台問題不斷。如何平穩擴展 K8s 平台變得至關重要。

1前言

距離上一次分享我們在 Pinterest 上搭建 Kubernetes 之旅已經過去一年多了。從那時開始,我們交付了許多功能,方便用戶進行採用,確保可靠性和可延展性,並積累了很多運維經驗和最佳實踐。

總的來說,Kubernetes 平台的用戶反饋都很正面。根據我們的調查,在用戶心中排行前三的好處分別是,減輕管理計算資源的負擔、更好的資源和故障隔離,以及更靈活的容量管理。

在 2020 年底,我們在 Kubernetes 集群中利用超過 2,500 個節點,協調了超過 35,000 個用於支持 Pinterest 各項業務的 Pod,而這項數據的增長依舊如火箭般竄升。

22020 年概況

隨著用戶採用的不斷增加,負載的種類和數量也在不斷增長。這就代表著 Kubernetes 平台需要有更強的可擴展性,才能跟得上日益增長的負載管理、Pod 的調度和放置,以及分配和取消分配節點的工作量。隨著更多關鍵業務的負載被搬上 Kubernetes 平台,用戶對平台可靠性的期望自然也水漲船高。

全平台範圍的停機也的確發生過。2020 年初,在我們一個集群上,短時間內有大量的 Pod 被創建,數量超過了計劃容量的三倍,導致該集群的自動協調器啟用了 900 個節點以滿足需求。kube-apiserver 率先開始出現延遲峰值以及錯誤率的增長,隨後便因資源限制而被 OOM 殺進程(Out of Memory Kill,內存不足時殺進程)。來自 Kubelets 的非綁定重試請求導致 kube-apiserver 負載猛增 7 倍。寫入請求數量的爆發導致 etcd 提前到達其總數據量的限制,並開始拒絕所有的寫入請求,平台無法繼續管理負載。為了緩解這次事件,我們不得不通過執行 etcd 操作來恢復平台運行,例如壓縮舊版本程序,碎片整理冗餘空間,以及禁用警報。此外,我們還得暫時擴容承載 kube-apiserver 和 etcd 的 Kubernetes 主節點,以減少對資源的限制。

和可延展性,並積累了很多運維經驗和最佳實踐。總的來說,Kube

Kubernetes API 伺服器延遲峰值

在 2020 年下半年,我們的一個基礎設施組件在 kube-apiserver 的集成中出了一個 bug,表現是短時間內生成大量的、對所有 kube-apiserver 的 Pod 和節點的昂貴查詢。這導致了 Kubernetes 的主節點資源使用量激增,kube-apiserver 進入了 OMM Kill 的狀態。幸運的是,這個出 bug 的組件被發現得很早,並且很快就回滾了。但在這次的事件中,平台的性能受到了降級的影響,其中包括負載的處理出現了延遲以及陳舊的服務狀態。

去一年多了。從那時開始,我們交付了許多功能,方便用戶進行採用,確保可靠性

Kubernetes API 伺服器執行 OOM Killed

3為規模化做好準備

在我們的 Kubernetes 之旅中,我們不斷反思自己平台的治理、彈性和可操作性,尤其是在當事故發生在我們最薄弱的地方時。對於一個工程資源有限的小團隊,我們必須要深入思考,找出問題的根本所在,確定短板的文職,並根據回報與成本的性價比確定解決方案的優先次序。我們面對複雜的 Kubernetes 生態系統時的策略是,儘量減少方案與社區中提供方法的分別的同時不斷回饋社區,但仍不放棄自己編寫內部組件代碼的可能性。

分享我們在Pinterest上搭建Kubernetes之旅已經過

Pinterest 上的 Kubernetes 平台架構(藍色代表我們自己編寫的內容,綠色則是開源內容)

4治理

資源配額的執行

Kubernetes 已有的資源配額管理確保了任何的命名空間都無法在絕大多數的維度上 無限制 地請求或占用資源,無論是 Pod、CPU 還是內存。如我們在前文的故障中所提到的,單個命名空間中數量激增的 Pod 創建事件可能會讓 kube-apiserver 過載,導致級聯故障。為確保其穩定性,單個命名空間的資源使用量都應有一定限制,這一點很重要。

這項任務的難點之一在於,在每一個命名空間強制執行資源配額需要一個潛在條件:所有的 Pod 和容器都需規定資源的請求和限制。在 Pinterest 的 Kubernetes 平台上,不同命名空間的負載屬於不同的團隊和不同的項目,而平台用戶則是通過 Pinterest 的 CRD 配置他們的負載。我們對這一問題的解決方案是,為 GRD 的轉換層中所有的 Pod 和容器添加默認資源請求和限制。

除此之外,我們還在 CRD 的驗證層中拒絕了所有未規定資源請求和限制的 Pod。

另一難點則在於,如何簡化跨團隊和組織的配額管理。為了資源配額的安全實現,我們參考了過往的資源使用情況,在其高峰值的基礎上額外增加 20% 的淨空,並將其設置為所有項目資源配額的初始值。我們創建了一個定時任務來監控配額的使用情況,如果某個項目的用量接近一定限度,會在營業時間內向負責該項目的團隊發送警報。這項設置鼓勵了負責團隊對項目進行更好的容量規劃,並在資源配額發生變動時提出申請。資源配額的變更在人工審核並簽署之後,才會進行自動部署。

客戶端訪問的執行

我們強制要求了所有的 KubeAPI 客戶端都遵循 Kubernetes 已有的最佳實踐:

控制器框架

控制器框架為優化讀取操作提供了一個利用 informer-reflector-cache 的、可共享的緩存架構。Informer 通過 kube-apiserver 監控目標對象,Reflector 將目標對象的變更反應到底層緩存(Cache)中,並將觀測到的事件傳播給事件處理程序。同一控制器中的多個組件可以為 OnCreate、OnUpdate,以及 OnDelete 事件註冊 Informer 事件處理程序,並從 Cache 中獲取對象(而非是直接從 Kube-apiserver 中獲取)。這樣一來,就減少了很多不必要或多餘的調用。

平穩擴展K8s平台變得至關重要。1前言距離上一次

Kubernetes 的控制器架構

速率限制

Kubernetes 的 API 客戶端通常會在不同的控制器中共享,而 API 是在不同的線程中調用的。Kubernetes 的 API 客戶端是與它支持的可配置 QPS 和 burst 的 token 桶速率限制器相綁定的,burst 超過閾值就節制 API 的調用,這樣單個的控制器就不會影響到 kube-apiserver 的帶寬。

共享緩存

除了控制器框架自帶 kube-apiserver 內置緩存之外,我們還在平台的 API 中添加了另一個基於 Informer 的寫通緩存層。這種設置是為了防止不必要的讀取調用對 kube-apiserver 的衝擊,重複利用伺服器端的緩存也可以避免應用程式代碼中過於繁雜的客戶端。

對於 從應用中 訪問 kube-apiserver 的情況,我們強制要求所有的請求都需要通過平台 API,利用共享緩存為訪問控制和流量控制分配安全身份。對於 從負載器 訪問 kube-apiserver 的情況,我們強制要求所有控制器的實現都是要基於帶有速率限制的控制框架。

5恢復力

硬化 Kubelet

Kubernetes 的控制平台會進入級聯故障的一個關鍵原因是,傳統的反射器(Reflector)的實現在處理錯誤時會有 無限制次數 的重試。這種小瑕疵在有些時候會被無限放大,尤其時當 API 伺服器被 OMM Kill 時,很容易造成集群上所有的反射器一起進行同步。

為了解決這個問題,我們通過與社區的緊密合作,反饋問題、討論解決方案,並最終讓我們的 pull request 通過審核並成功 merge。我們的想法是通過在反射器的 ListWatch 重試邏輯中添加指數回退,這樣,當 kube-apiserver 過載或請求失敗時,kubelet 和其他的控制器就不會繼續嘗試 kube-apiserver 了。這種彈性的改進在大多數的情況下都是錦上添花,但我們也發現,隨著 Kubernetes 集群中節點和 Pod 數量的增加,這種改進的必要性也體現出來了。

調整並發請求

隨著我們管理的節點的數量的增加,負載的創建和銷毀速度越快,QPS 伺服器需要處理的 API 調用數量也在增加。我們首先根據預估的負載大小,上調了變異和非變異操作的最大並發 API 調用的次數。這兩項設置將限制需要處理的 API 調用次數不能超過配置的數量,從而使 kube-apiserver 的 CPU 和內存消耗保持在一定的閾值之內。

在 Kubernetes 的 API 請求處理鏈中,每個請求在最開始都需要通過一連串的過濾器。最大機上 API 調用的限制則是在過濾器鏈中實現的。對於超過配置閾值的 API 調用,客戶端會收到「請求過多(429)」的反饋,從而觸發對應的重試操作。在未來,我們計劃對 EventRateLimit 功能進行更深入的研究,用更精細的准入控制提供更高的服務質量。

緩存更多的歷史紀錄

Watch 緩存時 kube-apiserver 內部的一種機制,它將各類資源中過去的事件緩存到一個環形緩存區中,以方便特定版本的 watch 調用。緩存區越大,伺服器能保存的事件就更多,連接中斷時為客戶端提供的事件流也就更流暢。鑑於這一事實,我們還改進了 kube-apiserver 的目標 RAM 大小,其內部最終會轉移到 Watch 緩存容量中,以提供更穩健的事件流。Kube-apiserver 有提供更詳細的配置更詳細的 Watch 緩存大小的方法,可以用於更精細的緩存需求。

etes之旅。但隨著用戶激增,負載飆升,其K8s平台問題不斷。如何

Kubernetes 的 Watch 緩存

6可操作性

可視性

為減少事故檢測和緩解的事件,我們不斷改善 Kubernetes 控制平面的可視性。這一點的挑戰在於要如何平衡故障檢測的覆蓋率和信號的靈敏度。對於現有的 Kubernetes 指標,我們通過分流並挑選重要區域進行監測和報警,如此一來,我們就可以更加主動地發現問題所在。除此之外,我們還對 kube-apiserver 進行監測,以覆蓋更細小的區域,從而更快地縮小問題根源所在區域。最後,我們調整了警報統計和閾值大小,以減少噪音和錯誤警報。

在高層次上,我們通過查看 QPS 和並發請求、錯誤率,以及請求延遲來監控 kube-apiserver 的負載。我們也可以將流量按照資源類型、請求動詞以及相關的服務帳號進行細分。而對於 listing 這類的昂貴流量,我們通過對象計數和字節大小來計算請求負載,即使只有很小的 QPS,這類流量也很容易導致 kube-apiserver 過載。最後,我們還監測了 etcd 的 watch 事件處理 QPS 和延遲處理的計數,以作為重要的伺服器性能指標。

,類似於中國小紅書。2017年,Pinterest走上Kubern

Kubernetes API 調用類型分類

可調試性

為了能更好地了解 Kubernetes 控制面板的性能和資源消耗,我們還用 boltdb 庫和 flamegraph 搭建了一個 etcd 數據存儲分析工具,以便對數據存儲的細化進行可視化展示。數據存儲分析的結果讓用戶可以洞察其內部,更便於進行優化。

作為美國知名的圖片社交網站,Pinterest坐擁3億用戶

單個密鑰空間的 Etcd 數據用量

除此之外,我們還啟用了 Go 語言的剖析工具 pprof 以及可視化的堆內存足跡,以快速找出資源最密集的代碼路徑和請求模式,一個例子是,列表資源調用的轉換響應對象。在我們調查 kube-apiserver 的 OOM 時發現的另一個大問題是,kube-apiserver 使用的頁面緩存是被計入 cgroup 的內存限制的,而通過使用匿名內存可以盜取同一 cgroup 的頁面緩存用量。於是,即使 kube-apiserver 只有 20GB 的堆內存用量,整個 cgroup 的 200GB 內存用量也有可能到達上限。雖然目前的內核默認設置是不主動回收分配的頁面以有效地重複利用,但我們目前仍然在研究基於 memory.stat 文件的設置的監控,並強制要求 cgroup 在內存使用接近上限時儘可能多地回收頁面。

nsonQian譯者|馬可薇策劃|萬佳

Kubernetes API 伺服器的內存詳情

7總結

通過在治理、彈性和可操作性方面的努力,我們在很大程度上避免了計算資源、控制面板帶寬方面的用量激增情況,確保了整個平台的性能和穩定性。優化後的 kube-apiserver 減少了 90% 的 QPS(主要是讀取),使得 kube-apiserver 的用量更加穩定、高效、健壯。我們從中學習到的關於 Kubernetes 內部的深入認知和額外見解,讓我們的能夠更好地進行系統操作和集群維護。

AnsonQian架構頭條作者|A

優化推出後 Kube-apiserver 的 QPS 減少情況

以下是我們在這段旅程中的一些重要收穫,希望能夠對你在處理 Kubernetes 的可擴展性和可靠性問題上有所幫助:

  • 診斷問題並找到其 根源 所在。在考慮「怎麼辦」之前先搞清楚問題「是什麼」。解決問題的第一步是了解瓶頸在哪以及其生成原因。如果你找到了問題的根本,那麼你已經掌握了一半的解決方案。
  • 首先嘗試 小規模漸進式 的優化,而不是直接上手激進的架構改革。在大多數情況下,這種方法不會讓你吃太大的虧,這點在資源不足的小團隊中也是很重要的。
  • 在規劃或調整調查和修復的優先順序時,請將 數據 作為參考憑據。正確的遙測技術可以幫助你在決定優化項目順序時做出更好的決定。
  • 關鍵的基礎設施組件在設計時應考慮到其復原力。分布式系統總是會出現故障的,我們總要做好 最壞的打算。正確的防護可以有效防止級聯故障,並將事故的影響範圍最小化。

8展望未來

聯邦

隨著我們規模的穩步增長,單一集群架構已經不足以支持日益增加的負載。目前的單一集群環境是高效且穩定的,我們的下一個里程碑即是將這個計算平台向橫向擴展。通過利用聯邦框架,我們的目標是以最小的操作開銷將新的集群插入到環境中去,同時保持終端用戶平台界面的穩定。我們的聯邦集群環境目前還在開發階段,期待它在產品化後能為我們帶來更多的可能性。

容量規劃

我們目前採用的資源配額的執行方法是簡化後的、並依賴反應的容量規劃方式。隨著我們不斷添加用戶的負載和系統組件,平台的動態變化、項目的等級,或者是集群範圍的容量限制可能無法跟上版本的變化。我們希望能夠探索出一種主動的容量規劃方案,根據歷史數據、增長軌跡,以及涵蓋資源配額和 API 配額的複雜的容量模型進行預測。這種更主動,也更準確的容量規劃可以有效防止平台的過度承諾和交付不足。

原文連結:

https://medium.com/pinterest-engineering/scaling-kubernetes-with-assurance-at-pinterest-a23f821168da?fileGuid=prJWDc8Hk9cjRkvJ

聲明:文章觀點僅代表作者本人,PTTZH僅提供信息發布平台存儲空間服務。
喔!快樂的時光竟然這麼快就過⋯
繼續其他精彩內容吧!
more