筆記。 翻譯。:歐洲旅遊聚合商 Omio 的這段令人大開眼界的歷史,帶領讀者從基礎理論到 Kubernetes 配置的迷人實踐複雜性。 熟悉此類案例不僅有助於開拓視野,還能防止出現不小的問題。
您是否曾經遇到過應用程式卡在原地、停止回應運行狀況檢查並且無法找出原因的情況? 一個可能的解釋與 CPU 資源配額限制有關。 這就是我們將在本文中討論的內容。
TL; DR:
如果您使用的 Linux 核心版本存在 CFS 配額錯誤,我們強烈建議您在 Kubernetes 中停用 CPU 限制(或在 Kubelet 中停用 CFS 配額)。 在核心
在大米奧 整個基礎設施由 Kubernetes 管理。 我們所有的有狀態和無狀態工作負載都專門在 Kubernetes 上運作(我們使用 Google Kubernetes Engine)。 在過去六個月中,我們開始觀察到隨機放緩。 應用程式凍結或停止回應健康檢查、失去網路連線等。 這種行為讓我們困惑了很長一段時間,最後我們決定認真看待這個問題。
文章摘要:
- 關於容器和 Kubernetes 的一些話;
- CPU請求和限制是如何實現的;
- CPU 限制在多核心環境中如何運作;
- 如何追蹤CPU節流;
- 問題的解決方案和細微差別。
關於容器和 Kubernetes 的幾句話
Kubernetes 本質上是基礎設施領域的現代標準。 它的主要任務是容器編排。
集裝箱
過去,我們必須創建 Java JAR/WAR、Python Egg 或可執行檔等工件才能在伺服器上運行。 然而,要使它們發揮作用,還必須完成額外的工作:安裝執行環境(Java/Python)、將必要的檔案放置在正確的位置、確保與特定版本的作業系統的相容性等。 換句話說,必須特別注意組態管理(這通常是開發人員和系統管理員之間爭論的根源)。
容器改變了一切。 現在這個工件是一個容器鏡像。 它可以表示為一種擴展的可執行文件,不僅包含程序,還包含成熟的執行環境(Java / Python / ...),以及預先安裝並準備好運行的必要文件/包跑步。 容器可以部署並運行在不同的伺服器上,無需任何額外的步驟。
此外,容器在自己的沙箱環境中運作。 它們有自己的虛擬網路適配器、存取受限的檔案系統、進程層次結構、CPU 和記憶體限制等。所有這些都是透過 Linux 核心的一個特殊子系統——命名空間來實現的。
Kubernetes
如前所述,Kubernetes 是一個容器編排器。 它的工作原理是這樣的:你給它一個機器池,然後說:「嘿,Kubernetes,讓我們啟動十個容器實例,每個實例有2 個處理器和3 GB 內存,並讓它們保持運行! 」 Kubernetes 將處理剩下的事情。 它將查找可用容量、啟動容器並在必要時重新啟動它們、在更改版本時推出更新等。 從本質上講,Kubernetes 可讓您抽像出硬體元件,並使各種系統適合部署和運行應用程式。
從外行人的角度來看 Kubernetes
Kubernetes 中的請求和限制是什麼
好的,我們已經介紹了容器和 Kubernetes。 我們也知道多個容器可以駐留在同一台機器上。
可以用公共公寓進行類比。 寬敞的場地(機器/單元)被佔用並出租給幾個租戶(貨櫃)。 Kubernetes 充當房地產經紀人。 那麼問題來了,如何避免租客之間發生衝突呢? 比如說,如果其中一個人決定借用浴室半天怎麼辦?
這就是請求和限制發揮作用的地方。 中央處理器 要求 僅需用於規劃目的。 這就像容器的“願望清單”,用於選擇最合適的節點。 同時CPU 限制 可以與租賃協議進行比較——一旦我們選擇了貨櫃單元, 不能 超越既定的界限。 這就是問題出現的地方......
請求和限制在 Kubernetes 中是如何實現的
Kubernetes 使用核心內建的節流機制(跳過時脈週期)來實現 CPU 限制。 如果應用程式超出限制,則會啟用限制(即,它接收較少的 CPU 週期)。 記憶體請求和限制的組織方式不同,因此更容易檢測。 為此,只需檢查 pod 最後的重啟狀態:是否為「OOMKilled」。 CPU 限制不那麼簡單,因為 K8s 只根據使用情況提供指標,而不是根據 cgroup 提供指標。
CPU請求
CPU請求是如何實現的
為了簡單起見,我們以 4 核心 CPU 的機器為例看一下流程。
K8s 使用控制組機制(cgroups)來控制資源(記憶體和處理器)的分配。 可以使用分層模型:子組繼承父組的限制。 分發詳細資訊儲存在虛擬檔案系統中(/sys/fs/cgroup
)。 對於處理器來說,這是 /sys/fs/cgroup/cpu,cpuacct/*
.
K8s使用文件 cpu.share
分配處理器資源。 在我們的例子中,根 cgroup 獲得 4096 個 CPU 資源份額 - 100% 的可用處理器能力(1 個核心 = 1024;這是一個固定值)。 根組根據註冊的後代的份額按比例分配資源 cpu.share
,而他們又對他們的後代做同樣的事情,等等。 在典型的 Kubernetes 節點上,根 cgroup 有三個子級: system.slice
, user.slice
и kubepods
。 前兩個子群組用於在關鍵系統負載和 K8 外部的使用者程式之間分配資源。 最後一個 - kubepods
— 由 Kubernetes 創建,用於在 Pod 之間分配資源。
上圖顯示第一組和第二組分別收到了 1024 共享,分配了 kuberpod 子組 4096 分享這怎麼可能:畢竟 root 群組只能訪問 4096 股份,而她的後代的股份總和大大超過了這個數字(6144)? 關鍵在於該值具有邏輯意義,因此 Linux 調度程序 (CFS) 使用它來按比例分配 CPU 資源。 在我們的例子中,前兩組收到 680 實際份額(16,6 的 4096%),kubepod 收到剩餘的份額 2736 分享如果發生停機,前兩組將不會使用分配的資源。
幸運的是,調度程序有一種機制可以避免浪費未使用的 CPU 資源。 它將「閒置」容量轉移到全域池,然後將其分配給需要額外處理器能力的群組(轉移分批進行,以避免舍入損失)。 類似的方法適用於後代的所有後代。
這一機制確保了處理器能力的公平分配,並確保沒有一個進程從其他進程「竊取」資源。
CPU限制
儘管 K8 中的限制和請求的配置看起來很相似,但它們的實作卻截然不同: 最有誤導性 以及記錄最少的部分。
K8s 參與 cfs_period_us
и cfs_quota_us
在 cgroup 目錄中(該檔案也位於那裡 cpu.share
).
不像 cpu.share
,配額是基於 時段,而不是可用的處理器能力。 cfs_period_us
指定週期(紀元)的持續時間 - 它始終為 100000 μs (100 ms)。 K8s 中有一個選項可以更改此值,但目前僅在 alpha 中可用。 調度程序使用紀元來重新啟動已使用的配額。 第二個文件 cfs_quota_us
,指定每個時期的可用時間(配額)。 請注意,它也以微秒為單位指定。 配額可能超過紀元長度; 換句話說,它可能大於100毫秒。
讓我們來看看 16 核心電腦(Omio 最常見的電腦類型)上的兩個場景:
場景 1:2 個執行緒和 200 毫秒限制。 無節流
場景 2:10 個執行緒和 200 毫秒限制。 20 毫秒後開始限制,再過 80 毫秒後恢復對處理器資源的訪問
假設您將 CPU 限制設為 2 內核; Kubernetes 會將此值轉換為 200 毫秒。 這意味著容器最多可以使用 200ms 的 CPU 時間而不進行限制。
這就是樂趣的開始。 如上所述,可用配額為 200 毫秒。 如果您並行工作 十 12 核機器上的執行緒(請參閱場景2 的插圖),當所有其他pod 都空閒時,配額將在短短20 毫秒內耗盡(因為10 * 20 毫秒= 200 毫秒),並且該pod 的所有執行緒都將掛起» (風門) 接下來的 80 毫秒。 已經提到的
如何評估 Pod 中的節流?
只需登入 pod 並執行 cat /sys/fs/cgroup/cpu/cpu.stat
.
-
nr_periods
— 調度程序週期總數; -
nr_throttled
— 合成中的節流週期數nr_periods
; -
throttled_time
— 以奈秒為單位的累積節流時間。
究竟發生了什麼事?
因此,我們在所有應用程式中都會受到高限制。 有時他在 一次半 比計算的還要強!
這會導致各種錯誤 - 就緒檢查失敗、容器凍結、網路連線中斷、服務呼叫逾時。 這最終會導致延遲增加和錯誤率更高。
決定和後果
這裡一切都很簡單。 我們放棄了 CPU 限制,開始將叢集中的作業系統核心更新到最新版本,修復了該錯誤。 我們服務中的錯誤(HTTP 5xx)數量立即顯著下降:
HTTP 5xx 錯誤
一項關鍵服務的 HTTP 5xx 錯誤
反應時間 p95
關鍵服務請求延遲,第 95 個百分點
營運成本
實例花費的小時數
捕獲量是多少?
如文章開頭所說:
可以與公共公寓進行類比…Kubernetes 充當房地產經紀人。 但如何避免租客之間發生衝突呢? 比如說,如果其中一個人決定借用浴室半天怎麼辦?
這就是問題所在。 一個不小心的容器可能會耗盡一台機器上所有可用的 CPU 資源。 如果你有一個智慧應用程式堆疊(例如,JVM、Go、Node VM 已正確配置),那麼這不是問題:你可以在這樣的條件下工作很長時間。 但如果應用程式優化不佳或根本沒有優化(FROM java:latest
),情況可能會失控。 在 Omio,我們擁有自動化的基本 Dockerfile,並為主要語言堆疊提供了足夠的預設設置,因此這個問題不存在。
我們建議監控指標
引用
這就是我們的故事。 以下材料極大地有助於了解正在發生的事情:
-
kernel.org → CFS 調度程序 ; -
kernel.org → CFS 頻寬控制 ; -
了解Linux容器調度 ; -
關於 Linux 容器您需要了解的一切,第一部分:Linux 控制組和進程隔離 ; -
Kubernetes 失敗案例 - 尋找「CPU 節流」。
Kubernetes 錯誤回報:
您在實務上是否遇到類似的問題或有容器化生產環境中與節流相關的經驗? 在評論中分享你的故事!
譯者PS
另請閱讀我們的博客:
- «
Kubernetes 中的自動擴展和資源管理(概述和視頻報告) “; - «
CPU 管理器在 Kubernetes 中的工作原理 “; - «
當您執行 kubectl run 時,Kubernetes 中會發生什麼事? 第2部分 “。
來源: www.habr.com