API 優先順序與公平性
Kubernetes v1.29 [穩定]
在過載情況下控制 Kubernetes API 伺服器的行為是叢集管理員的關鍵任務。kube-apiserver 有一些可用的控制項(即 --max-requests-inflight
和 --max-mutating-requests-inflight
命令列標誌)來限制將接受的未完成工作量,防止大量湧入的請求過載並可能導致 API 伺服器崩潰,但這些標誌不足以確保最重要的請求在高流量期間通過。
API 優先順序與公平性功能 (APF) 是一種替代方案,可以改進上述的最大並行限制。APF 以更精細的方式分類和隔離請求。它還引入了有限的排隊量,因此在非常短暫的突發情況下不會拒絕任何請求。請求使用公平排隊技術從佇列中分派,因此,例如,行為不良的控制器 不需要讓其他控制器挨餓(即使在相同的優先順序層級)。
此功能旨在與標準控制器良好協作,標準控制器使用 Informer,並以指數退避來回應 API 請求的失敗,以及其他也以這種方式工作的用戶端。
注意
某些被歸類為「長時間執行」的請求(例如遠端命令執行或日誌追蹤)不受 API 優先順序與公平性篩選器的約束。對於未啟用 API 優先順序與公平性功能的--max-requests-inflight
標誌也是如此。API 優先順序與公平性確實適用於 watch 請求。當 API 優先順序與公平性停用時,watch 請求不受 --max-requests-inflight
限制的約束。啟用/停用 API 優先順序與公平性
API 優先順序與公平性功能由命令列標誌控制,預設為啟用。有關可用的 kube-apiserver 命令列選項以及如何啟用和停用它們的一般說明,請參閱選項。APF 的命令列選項名稱為 "--enable-priority-and-fairness"。此功能還涉及一個API 群組,其中:(a)穩定 v1
版本,在 1.29 中引入,預設啟用(b)v1beta3
版本,預設啟用,並在 v1.29 中棄用。您可以透過將以下命令列標誌新增至您的 kube-apiserver
調用來停用 API 群組 Beta 版本 v1beta3
kube-apiserver \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta3=false \
# …and other flags as usual
命令列標誌 --enable-priority-and-fairness=false
將停用 API 優先順序與公平性功能。
遞迴伺服器情境
在遞迴伺服器情境中,必須謹慎使用 API 優先順序與公平性。這些情境是指某個伺服器 A 在處理請求時,向某個伺服器 B 發出附屬請求。也許伺服器 B 甚至可能向伺服器 A 發出進一步的附屬呼叫。在優先順序與公平性控制同時套用於原始請求和某些附屬請求的情況下(無論遞迴多深),都存在優先順序反轉和/或死鎖的風險。
遞迴的一個範例是當 kube-apiserver
向伺服器 B 發出許可 Webhook 呼叫時,以及在處理該呼叫時,伺服器 B 向 kube-apiserver
發出進一步的附屬請求。遞迴的另一個範例是當 APIService
物件指示 kube-apiserver
將關於特定 API 群組的請求委派給自訂外部伺服器 B 時(這是稱為「聚合」的事情之一)。
當已知原始請求屬於特定優先順序層級,並且附屬受控請求被分類為較高優先順序層級時,這是一種可能的解決方案。當原始請求可能屬於任何優先順序層級時,附屬受控請求必須免於優先順序與公平性限制。執行此操作的一種方法是使用配置分類和處理的物件(如下所述)。另一種方法是完全停用伺服器 B 上的優先順序與公平性,使用上述技術。第三種方法(當伺服器 B 不是 kube-apisever
時,這是最簡單的方法)是在程式碼中停用優先順序與公平性的情況下建置伺服器 B。
概念
API 優先順序與公平性功能涉及多個不同的功能。傳入的請求會使用FlowSchemas依請求的屬性進行分類,並指派給優先順序層級。優先順序層級透過維護個別的並行限制來增加隔離程度,因此指派給不同優先順序層級的請求不會彼此餓死。在優先順序層級內,公平排隊演算法可防止來自不同流的請求彼此餓死,並允許將請求排隊,以防止突發流量在平均負載可接受的情況下導致請求失敗。
優先順序層級
在未啟用 APF 的情況下,API 伺服器中的整體並行性受限於 kube-apiserver
標誌 --max-requests-inflight
和 --max-mutating-requests-inflight
。啟用 APF 後,這些標誌定義的並行限制會被加總,然後總和會分配到一組可配置的優先順序層級中。每個傳入的請求都會被分配到一個優先順序層級,而每個優先順序層級只會調度與其特定限制允許的數量相同的並行請求。
例如,預設配置包含用於領導者選舉請求、來自內建控制器請求以及來自 Pod 請求的獨立優先順序層級。這表示行為不良的 Pod 以請求淹沒 API 伺服器時,無法阻止領導者選舉或內建控制器成功執行動作。
優先順序層級的並行限制會定期調整,允許未充分利用的優先順序層級暫時將並行性借給高度利用的層級。這些限制基於名義限制以及關於優先順序層級可以借出多少並行性和可以借用多少並行性的界限,所有這些都來自下面提到的配置物件。
請求佔用的席位
以上關於並行性管理的描述是基本情況。請求具有不同的持續時間,但在任何給定時刻與優先順序層級的並行性限制進行比較時,它們被同等計數。在基本情況下,每個請求佔用一個並行性單位。詞語「席位」用於表示一個並行性單位,其靈感來自於火車或飛機上的每位乘客都佔用固定供應的席位之一的方式。
但是,有些請求佔用多個席位。其中一些是 list 請求,伺服器估計它們將傳回大量物件。人們發現這些請求對伺服器造成了異常沉重的負擔。因此,伺服器會估計將傳回的物件數量,並認為請求佔用的席位數量與估計的數量成正比。
watch 請求的執行時間調整
API 優先順序和公平性管理 watch 請求,但這涉及到與基本行為的幾個額外偏差。第一個偏差與 watch 請求佔用其席位的時間長度有關。根據請求參數,對 watch 請求的回應可能會也可能不會以所有相關預先存在物件的 create 通知開始。API 優先順序和公平性認為,一旦初始的通知爆發(如果有的話)結束,watch 請求就完成了其席位的佔用。
每當伺服器收到物件建立/更新/刪除的通知時,正常通知就會以並行爆發的方式傳送到所有相關的 watch 回應流。為了考慮到這項工作,API 優先順序和公平性認為每個寫入請求在實際寫入完成後都會花費一些額外的時間來佔用席位。伺服器會估計要傳送的通知數量,並調整寫入請求的席位數量和席位佔用時間,以包含這項額外的工作。
佇列
即使在一個優先順序層級內,也可能存在大量不同的流量來源。在過載情況下,防止一個請求流使其他請求流「餓死」是有價值的(尤其是在單一錯誤的用戶端以請求淹沒 kube-apiserver 的相對常見情況下,理想情況下,該錯誤的用戶端根本不會對其他用戶端產生明顯的影響)。這透過使用公平佇列演算法來處理分配到相同優先順序層級的請求來處理。每個請求都會被分配到一個流,該流由符合的 FlowSchema 的名稱加上一個流區分器來識別 — 該區分器可以是請求使用者、目標資源的命名空間或無 — 並且系統嘗試給予相同優先順序層級的不同流中的請求大致相等的權重。為了能夠區分不同實例的處理,具有多個實例的控制器應該使用不同的使用者名稱進行身份驗證
在將請求分類到一個流之後,API 優先順序和公平性功能然後可能會將請求分配到一個佇列。此分配使用一種稱為洗牌分片的技術,該技術相對有效地利用佇列來隔離低強度流和高強度流。
佇列演算法的詳細資訊對於每個優先順序層級都是可調整的,並且允許管理員權衡記憶體使用量、公平性(當總流量超過容量時,獨立流都將取得進展的特性)、對突發流量的容忍度以及佇列引起的額外延遲。
豁免請求
有些請求被認為非常重要,因此不受此功能施加的任何限制的約束。這些豁免防止配置不當的流控制配置完全停用 API 伺服器。
資源
流控制 API 涉及兩種資源。PriorityLevelConfigurations 定義可用的優先順序層級、每個層級可以處理的可用並行預算份額,並允許微調佇列行為。FlowSchemas 用於對個別的入站請求進行分類,將每個請求與單個 PriorityLevelConfiguration 匹配。
PriorityLevelConfiguration
PriorityLevelConfiguration 代表單個優先順序層級。每個 PriorityLevelConfiguration 對未完成請求的數量都有獨立的限制,並且對佇列請求的數量也有限制。
PriorityLevelConfiguration 的名義並行限制不是以席位的絕對數量指定的,而是以「名義並行份額」指定的。API 伺服器的總並行限制在現有的 PriorityLevelConfigurations 之間按比例分配,以給予每個層級以席位表示的名義限制。這允許叢集管理員透過重新啟動 kube-apiserver
並使用不同的 --max-requests-inflight
(或 --max-mutating-requests-inflight
)值來擴大或縮小伺服器的總流量,並且所有 PriorityLevelConfigurations 都將看到其允許的最大並行性按相同的比例增加(或減少)。
注意
在v1beta3
之前的版本中,相關的 PriorityLevelConfiguration 欄位名稱為「保證並行份額」而不是「名義並行份額」。此外,在 Kubernetes 1.25 和更早版本中,沒有定期調整:名義/保證限制始終在沒有調整的情況下應用。優先順序層級可以借出多少並行性和可以借用多少並行性的界限在 PriorityLevelConfiguration 中表示為層級名義限制的百分比。這些百分比透過乘以名義限制 / 100.0 並四捨五入來解析為席位的絕對數量。優先順序層級的動態調整並行限制被限制在 (a) 其名義限制減去其可借出席位的下限和 (b) 其名義限制加上其可以借用席位的上限之間。在每次調整時,動態限制是透過每個優先順序層級回收最近出現需求的任何借出席位,然後在剛剛描述的範圍內,共同公平地回應優先順序層級上的近期席位需求而得出的。
注意
啟用優先順序和公平性功能後,伺服器的總並行限制設定為--max-requests-inflight
和 --max-mutating-requests-inflight
的總和。不再區分變更請求和非變更請求;如果您想針對給定資源分別處理它們,請建立單獨的 FlowSchemas,分別匹配變更和非變更動詞。當分配給單個 PriorityLevelConfiguration 的入站請求量超過其允許的並行層級時,其規格的 type
欄位決定了額外請求將會發生什麼情況。Reject
類型表示超額流量將立即被拒絕,並出現 HTTP 429(請求過多)錯誤。Queue
類型表示超過閾值的請求將被放入佇列,並使用洗牌分片和公平佇列技術來平衡請求流之間的進度。
佇列配置允許調整優先順序層級的公平佇列演算法。演算法的詳細資訊可以在增強提案中閱讀,但簡而言之
增加
queues
會降低不同流之間衝突的機率,但會增加記憶體使用量。此處的值 1 有效地停用了公平佇列邏輯,但仍然允許請求排隊。增加
queueLengthLimit
允許在不丟棄任何請求的情況下維持更大的突發流量,但會增加延遲和記憶體使用量。變更
handSize
允許您調整不同流之間衝突的機率以及單個流在過載情況下可用的總並行性。注意
較大的handSize
使兩個個別流發生衝突的可能性降低(因此一個流能夠使另一個流「餓死」的可能性也降低),但少量流能夠主導 apiserver 的可能性更高。較大的handSize
也可能會增加單個高流量流可能造成的延遲量。來自單個流的可能佇列請求的最大數量為handSize * queueLengthLimit
。
以下是一個表格,顯示了一組有趣的洗牌分片配置,針對每個配置顯示了在說明性的象群數量集合中,給定的小鼠(低強度流)被象群(高強度流)擠壓的可能性。請參閱 https://play.golang.org/p/Gi0PLgVHiUg,它計算了此表格。
HandSize | Queues | 1 頭象 | 4 頭象 | 16 頭象 |
---|---|---|---|---|
12 | 32 | 4.428838398950118e-09 | 0.11431348830099144 | 0.9935089607656024 |
10 | 32 | 1.550093439632541e-08 | 0.0626479840223545 | 0.9753101519027554 |
10 | 64 | 6.601827268370426e-12 | 0.00045571320990370776 | 0.49999929150089345 |
9 | 64 | 3.6310049976037345e-11 | 0.00045501212304112273 | 0.4282314876454858 |
8 | 64 | 2.25929199850899e-10 | 0.0004886697053040446 | 0.35935114681123076 |
8 | 128 | 6.994461389026097e-13 | 3.4055790161620863e-06 | 0.02746173137155063 |
7 | 128 | 1.0579122850901972e-11 | 6.960839379258192e-06 | 0.02406157386340147 |
7 | 256 | 7.597695465552631e-14 | 6.728547142019406e-08 | 0.0006709661542533682 |
6 | 256 | 2.7134626662687968e-12 | 2.9516464018476436e-07 | 0.0008895654642000348 |
6 | 512 | 4.116062922897309e-14 | 4.982983350480894e-09 | 2.26025764343413e-05 |
6 | 1024 | 6.337324016514285e-16 | 8.09060164312957e-11 | 4.517408062903668e-07 |
FlowSchema
FlowSchema 匹配一些入站請求,並將它們分配到一個優先順序層級。每個入站請求都會針對 FlowSchemas 進行測試,從 matchingPrecedence
數值最低的 FlowSchemas 開始,然後向上進行。第一個匹配項獲勝。
注意
只有給定請求的第一個匹配 FlowSchema 才重要。如果多個 FlowSchemas 匹配單個入站請求,則將根據matchingPrecedence
最高的 FlowSchema 進行分配。如果多個具有相同 matchingPrecedence
的 FlowSchemas 匹配相同的請求,則名稱按字典順序較小的 FlowSchema 將獲勝,但最好不要依賴這一點,而是確保沒有兩個 FlowSchemas 具有相同的 matchingPrecedence
。如果 FlowSchema 的至少一個 rules
匹配給定請求,則該 FlowSchema 匹配該請求。如果規則的至少一個 subjects
和至少一個 resourceRules
或 nonResourceRules
(取決於傳入的請求是針對資源還是非資源 URL)匹配請求,則該規則匹配請求。
對於 subjects 中的 name
欄位,以及資源和非資源規則的 verbs
、apiGroups
、resources
、namespaces
和 nonResourceURLs
欄位,可以指定萬用字元 *
來匹配給定欄位的所有值,從而有效地將其從考慮中移除。
FlowSchema 的 distinguisherMethod.type
決定了如何將匹配該架構的請求分隔到流中。它可以是 ByUser
,在這種情況下,一個請求使用者將無法使其他使用者的容量「餓死」;ByNamespace
,在這種情況下,對一個命名空間中資源的請求將無法使對其他命名空間中資源的請求的容量「餓死」;或者空白(或者可以完全省略 distinguisherMethod
),在這種情況下,此 FlowSchema 匹配的所有請求都將被視為單個流的一部分。給定 FlowSchema 的正確選擇取決於資源和您的特定環境。
預設值
每個 kube-apiserver 都維護兩種 APF 配置物件:強制性和建議性。
強制性配置物件
四個強制性配置物件反映了固定的內建護欄行為。這是伺服器在這些物件存在之前就有的行為,並且當這些物件存在時,它們的規格反映了這種行為。四個強制性物件如下。
強制性
exempt
優先順序層級用於完全不受流控制約束的請求:它們將始終立即調度。強制性exempt
FlowSchema 將來自system:masters
群組的所有請求分類到此優先順序層級。如果適用,您可以定義其他 FlowSchemas,將其他請求導向此優先順序層級。強制性
catch-all
優先順序層級與強制性catch-all
FlowSchema 結合使用,以確保每個請求都獲得某種分類。通常,您不應依賴此 catch-all 配置,而應建立您自己的 catch-all FlowSchema 和 PriorityLevelConfiguration(或使用預設安裝的建議性global-default
優先順序層級),視情況而定。由於預期不會正常使用它,因此強制性catch-all
優先順序層級具有非常小的並行份額,並且不會將請求排隊。
建議性配置物件
建議性的 FlowSchemas 和 PriorityLevelConfigurations 構成合理的預設配置。如果您願意,您可以修改這些配置物件和/或建立其他配置物件。如果您的叢集很可能遇到重負載,那麼您應該考慮哪種配置效果最佳。
建議的配置將請求分為六個優先順序層級
node-high
優先順序層級用於來自節點的健康狀態更新。system
優先順序層級用於來自system:nodes
群組的非健康狀態請求,即 Kubelets,它們必須能夠聯絡 API 伺服器,工作負載才能夠在其上排程。leader-election
優先順序層級用於來自內建控制器的領導者選舉請求(特別是來自system:kube-controller-manager
或system:kube-scheduler
使用者和kube-system
命名空間中服務帳戶的endpoints
、configmaps
或leases
請求)。將這些請求與其他流量隔離非常重要,因為領導者選舉失敗會導致其控制器失敗並重新啟動,這反過來會導致更多昂貴的流量,因為新的控制器會同步其 informers。workload-high
優先順序層級用於來自內建控制器的其他請求。workload-low
優先順序層級用於來自任何其他服務帳戶的請求,這通常包括來自在 Pod 中執行的控制器的所有請求。global-default
優先順序層級處理所有其他流量,例如非特權使用者執行的互動式kubectl
命令。
建議性的 FlowSchemas 用於將請求導向上述優先順序層級,此處不再列舉。
強制性和建議性配置物件的維護
每個 kube-apiserver
都獨立維護強制性和建議性配置物件,使用初始行為和定期行為。因此,在不同版本的伺服器混合存在的情況下,只要不同的伺服器對這些物件的正確內容有不同的意見,就可能會發生抖動。
每個 kube-apiserver
都對強制性和建議性配置物件進行初始維護遍歷,然後對這些物件進行定期維護(每分鐘一次)。
對於強制性配置物件,維護包括確保物件存在,並且如果物件存在,則具有正確的規格。伺服器拒絕允許建立或更新規格與伺服器的護欄行為不一致的物件。
建議性配置物件的維護旨在允許覆寫其規格。另一方面,刪除不受尊重:維護將還原物件。如果您不想要建議性配置物件,那麼您需要保留它,但將其規格設定為具有最小的後果。建議性物件的維護也旨在支援在推出新版本的 kube-apiserver
時進行自動遷移,儘管在伺服器混合存在時可能會發生抖動。
建議性配置物件的維護包括在物件不存在時建立它 — 使用伺服器的建議規格 — 。另一方面,如果物件已存在,則維護行為取決於 kube-apiservers
還是使用者控制物件。在前一種情況下,伺服器確保物件的規格是伺服器建議的規格;在後一種情況下,規格保持不變。
誰控制物件的問題首先透過尋找具有鍵 apf.kubernetes.io/autoupdate-spec
的註釋來解答。如果存在這樣的註釋並且其值為 true
,則 kube-apiservers 控制物件。如果存在這樣的註釋並且其值為 false
,則使用者控制物件。如果這兩種情況都不成立,則會諮詢物件的 metadata.generation
。如果為 1,則 kube-apiservers 控制物件。否則,使用者控制物件。這些規則在 1.22 版本中引入,它們對 metadata.generation
的考量是為了從更簡單的早期行為遷移。希望控制建議性配置物件的使用者應將其 apf.kubernetes.io/autoupdate-spec
註釋設定為 false
。
強制性或建議性配置物件的維護還包括確保它具有 apf.kubernetes.io/autoupdate-spec
註釋,該註釋準確地反映了 kube-apiservers 是否控制物件。
維護還包括刪除既不是強制性也不是建議性,但註釋為 apf.kubernetes.io/autoupdate-spec=true
的物件。
健康檢查並行性豁免
建議的配置沒有對來自其本地 kubelets 的 kube-apiservers 健康檢查請求給予特殊處理 --- 這些請求傾向於使用安全埠,但不提供憑證。使用建議的配置,這些請求被分配到 global-default
FlowSchema 和對應的 global-default
優先順序層級,其他流量可能會將它們擠出。
如果您新增以下額外的 FlowSchema,這將使這些請求免於速率限制。
注意
進行此變更也允許任何惡意方隨後發送符合此 FlowSchema 的健康檢查請求,並且可以任意量發送。如果您有 Web 流量篩選器或類似的外部安全機制來保護叢集的 API 伺服器免受一般網際網路流量的影響,您可以配置規則來封鎖任何來自叢集外部的健康檢查請求。apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
name: health-for-strangers
spec:
matchingPrecedence: 1000
priorityLevelConfiguration:
name: exempt
rules:
- nonResourceRules:
- nonResourceURLs:
- "/healthz"
- "/livez"
- "/readyz"
verbs:
- "*"
subjects:
- kind: Group
group:
name: "system:unauthenticated"
可觀察性
指標
注意
在 Kubernetes v1.20 之前的版本中,標籤flow_schema
和 priority_level
的名稱不一致,分別為 flowSchema
和 priorityLevel
。如果您執行的是 Kubernetes v1.19 和更早版本,您應該參考您版本的說明文件。當您啟用 API 優先順序和公平性功能時,kube-apiserver 會匯出額外的指標。監控這些指標可以幫助您確定您的配置是否不適當地限制了重要流量,或者找出可能損害系統健康狀態的不良行為工作負載。
成熟度層級 BETA
apiserver_flowcontrol_rejected_requests_total
是一個計數器向量(自伺服器啟動以來累積),用於統計被拒絕的請求,按標籤flow_schema
(指示匹配請求的 FlowSchema)、priority_level
(指示請求分配到的優先順序層級)和reason
分解。reason
標籤將是以下值之一queue-full
,表示已佇列的請求過多。concurrency-limit
,表示 PriorityLevelConfiguration 配置為拒絕而不是佇列超額請求。time-out
,表示請求在其佇列時間限制到期時仍在佇列中。cancelled
,表示請求未被清除鎖定,並且已從佇列中彈出。
apiserver_flowcontrol_dispatched_requests_total
是一個計數器向量(自伺服器啟動以來累積),用於統計已開始執行的請求,按flow_schema
和priority_level
分解。apiserver_flowcontrol_current_inqueue_requests
是一個計量向量,用於保存佇列中(未執行)請求的瞬時數量,按priority_level
和flow_schema
分解。apiserver_flowcontrol_current_executing_requests
是一個計量向量,用於保存正在執行(未在佇列中等待)請求的瞬時數量,按priority_level
和flow_schema
分解。apiserver_flowcontrol_current_executing_seats
是一個計量向量,用於保存已佔用席位的瞬時數量,按priority_level
和flow_schema
分解。apiserver_flowcontrol_request_wait_duration_seconds
是一個直方圖向量,用於統計請求在佇列中花費的時間長度,按標籤flow_schema
、priority_level
和execute
分解。execute
標籤指示請求是否已開始執行。注意
由於每個 FlowSchema 始終將請求分配到單個 PriorityLevelConfiguration,您可以將一個優先順序層級的所有 FlowSchemas 的直方圖相加,以獲得分配到該優先順序層級的請求的有效直方圖。apiserver_flowcontrol_nominal_limit_seats
是一個計量向量,用於保存每個優先順序層級的名義並行限制,該限制是根據 API 伺服器的總並行限制和優先順序層級配置的名義並行份額計算得出的。
成熟度層級 ALPHA
apiserver_current_inqueue_requests
是一個計量向量,用於統計最近佇列請求數量的高水位標記,按名為request_kind
的標籤分組,該標籤的值為mutating
或readOnly
。這些高水位標記描述了最近完成的一秒鐘窗口中看到的最大數量。這些高水位標記補充了較舊的apiserver_current_inflight_requests
計量向量,該向量保存了上一個窗口中正在主動服務的請求數量的高水位標記。apiserver_current_inqueue_seats
是一個計量向量,用於統計佇列請求中每個請求將佔用的最大席位數量的總和,按標籤flow_schema
和priority_level
分組。apiserver_flowcontrol_read_vs_write_current_requests
是一個直方圖向量,用於統計每次奈秒結束時的觀察值,即按標籤phase
(取值為waiting
和executing
)和request_kind
(取值為mutating
和readOnly
)分解的請求數量。每個觀察值都是一個介於 0 和 1 之間的比率,即請求數量除以請求數量的相應限制(等待的佇列容量限制和執行的並行限制)。apiserver_flowcontrol_request_concurrency_in_use
是一個計量向量,用於保存已佔用席位的瞬時數量,按priority_level
和flow_schema
分解。apiserver_flowcontrol_priority_level_request_utilization
是一個直方圖向量,用於統計每次奈秒結束時的觀察值,即按標籤phase
(取值為waiting
和executing
)和priority_level
分解的請求數量。每個觀察值都是一個介於 0 和 1 之間的比率,即請求數量除以請求數量的相應限制(等待的佇列容量限制和執行的並行限制)。apiserver_flowcontrol_priority_level_seat_utilization
是一個直方圖向量,用於統計每次奈秒結束時的觀察值,即優先順序層級並行限制的利用率,按priority_level
分解。此利用率是(已佔用席位數量)/(並行限制)的比率。此指標考慮了所有執行階段(包括正常階段和寫入結束時為涵蓋相應通知工作而產生的額外延遲)的所有請求,但 WATCH 除外;對於 WATCH,它僅考慮交付預先存在物件通知的初始階段。向量中的每個直方圖也標記有phase: executing
(等待階段沒有席位限制)。apiserver_flowcontrol_request_queue_length_after_enqueue
是一個直方圖向量,用於統計佇列的佇列長度,按priority_level
和flow_schema
分解,由已佇列的請求抽樣。每個被放入佇列的請求都會為其直方圖貢獻一個樣本,報告請求新增後立即的佇列長度。請注意,這產生的統計數據與無偏調查產生的統計數據不同。注意
此處直方圖中的離群值表示很可能單個流(即,一個使用者或一個命名空間的請求,取決於配置)正在淹沒 API 伺服器,並且正在受到限制。相比之下,如果一個優先順序層級的直方圖顯示該優先順序層級的所有佇列都比其他優先順序層級的佇列長,則可能適合增加該 PriorityLevelConfiguration 的並行份額。apiserver_flowcontrol_request_concurrency_limit
與apiserver_flowcontrol_nominal_limit_seats
相同。在引入優先順序層級之間的並行借用之前,這始終等於apiserver_flowcontrol_current_limit_seats
(後者作為一個單獨的指標不存在)。apiserver_flowcontrol_lower_limit_seats
是一個計量向量,用於保存每個優先順序層級的動態並行限制的下限。apiserver_flowcontrol_upper_limit_seats
是一個計量向量,用於保存每個優先順序層級的動態並行限制的上限。apiserver_flowcontrol_demand_seats
是一個直方圖向量,用於統計每次奈秒結束時的觀察值,即每個優先順序層級的(席位需求)/(名義並行限制)的比率。優先順序層級的席位需求是佇列請求和處於執行初始階段的請求的總和,即請求的初始和最終執行階段中佔用席位數量的最大值。apiserver_flowcontrol_demand_seats_high_watermark
是一個計量向量,用於保存每個優先順序層級在上次並行借用調整期間看到的最高席位需求。apiserver_flowcontrol_demand_seats_average
是一個計量向量,用於保存每個優先順序層級在上次並行借用調整期間看到的按時間加權的平均席位需求。apiserver_flowcontrol_demand_seats_stdev
是一個計量向量,用於保存每個優先順序層級在上次並行借用調整期間看到的按時間加權的席位需求母體標準差。apiserver_flowcontrol_demand_seats_smoothed
是一個計量向量,用於保存每個優先順序層級在上次並行調整時確定的平滑包絡席位需求。apiserver_flowcontrol_target_seats
是一個計量向量,用於保存每個優先順序層級進入借用分配問題的並行目標。apiserver_flowcontrol_seat_fair_frac
是一個計量向量,用於保存在上次借用調整中確定的公平分配分數。apiserver_flowcontrol_current_limit_seats
是一個計量向量,用於保存每個優先順序層級在上次調整中得出的動態並行限制。apiserver_flowcontrol_request_execution_seconds
是一個直方圖向量,用於統計請求實際執行所花費的時間長度,按flow_schema
和priority_level
分解。apiserver_flowcontrol_watch_count_samples
是一個直方圖向量,用於統計與給定寫入相關的活動 WATCH 請求的數量,按flow_schema
和priority_level
分解。apiserver_flowcontrol_work_estimated_seats
是一個直方圖向量,用於統計與請求相關的估計席位數量(初始階段和最終階段的最大值),按flow_schema
和priority_level
分解。apiserver_flowcontrol_request_dispatch_no_accommodation_total
是一個計數器向量,用於統計原則上可能導致請求被調度但由於缺乏可用並行性而未被調度的事件數量,按flow_schema
和priority_level
分解。apiserver_flowcontrol_epoch_advance_total
是一個計數器向量,用於統計嘗試將優先順序層級的進度計數器向後跳躍以避免數值溢位的次數,按priority_level
和success
分組。
使用 API 優先順序和公平性的良好實務
當給定優先順序層級超過其允許的並行性時,請求可能會遇到延遲增加或被丟棄並出現 HTTP 429(請求過多)錯誤。為了防止 APF 的這些副作用,您可以修改您的工作負載或調整您的 APF 設定,以確保有足夠的席位可用於服務您的請求。
要偵測請求是否因 APF 而被拒絕,請檢查以下指標
- apiserver_flowcontrol_rejected_requests_total:每個 FlowSchema 和 PriorityLevelConfiguration 拒絕的請求總數。
- apiserver_flowcontrol_current_inqueue_requests:每個 FlowSchema 和 PriorityLevelConfiguration 排隊中的目前請求數量。
- apiserver_flowcontrol_request_wait_duration_seconds:請求在佇列中等待所增加的延遲時間。
- apiserver_flowcontrol_priority_level_seat_utilization:每個 PriorityLevelConfiguration 的席位利用率。
工作負載修改
為了防止請求排隊並增加延遲,或因 APF 而被丟棄,您可以透過以下方式最佳化您的請求:
- 降低請求執行的速率。在固定的時間內減少請求數量,將會減少在特定時間需要的席位數量。
- 避免同時發出大量昂貴的請求。可以最佳化請求以使用更少的席位,或縮短延遲時間,以便這些請求佔用席位的時間更短。List 請求可能會佔用超過 1 個席位,具體取決於請求期間擷取的物件數量。限制 list 請求中檢索的物件數量,例如使用分頁,將在較短的時間內使用較少的總席位。此外,將 list 請求替換為 watch 請求將需要較低的總並行份額,因為 watch 請求在其初始通知爆發期間僅佔用 1 個席位。如果在 1.27 及更高版本中使用串流 list,watch 請求在其初始通知爆發期間將佔用與 list 請求相同數量的席位,因為必須串流集合的整個狀態。請注意,在這兩種情況下,watch 請求在初始階段之後都不會佔用任何席位。
請記住,來自 APF 的排隊或拒絕請求可能是由請求數量增加或現有請求的延遲時間增加所引起的。例如,如果通常需要 1 秒才能執行的請求開始需要 60 秒,則 APF 可能會開始拒絕請求,因為由於延遲時間增加,請求佔用席位的時間比平常更長。如果 APF 開始拒絕跨多個優先順序層級的請求,而工作負載沒有顯著變化,則可能是控制平面的效能存在潛在問題,而不是工作負載或 APF 設定。
優先順序和公平性設定
您也可以修改預設的 FlowSchema 和 PriorityLevelConfiguration 物件,或建立這些類型的新物件,以更好地適應您的工作負載。
APF 設定可以修改為:
- 為高優先順序請求提供更多席位。
- 隔離非必要或昂貴的請求,如果與其他流程共享並行層級,這些請求將會耗盡並行層級。
為高優先順序請求提供更多席位
- 如果可能,可以通過增加
max-requests-inflight
和max-mutating-requests-inflight
標誌的值,來增加特定kube-apiserver
的所有優先順序層級可用的席位數量。或者,水平擴展kube-apiserver
實例的數量將增加整個叢集中每個優先順序層級的總並行性,前提是請求有充分的負載平衡。 - 您可以建立一個新的 FlowSchema,該 FlowSchema 引用具有較大並行層級的 PriorityLevelConfiguration。這個新的 PriorityLevelConfiguration 可以是現有的層級,也可以是具有自己名義並行份額集的新層級。例如,可以引入一個新的 FlowSchema,將您的請求的 PriorityLevelConfiguration 從 global-default 更改為 workload-low,以增加可供您的使用者使用的席位數量。建立新的 PriorityLevelConfiguration 將會減少指定給現有層級的席位數量。請注意,編輯預設的 FlowSchema 或 PriorityLevelConfiguration 將需要將
apf.kubernetes.io/autoupdate-spec
註解設定為 false。 - 您也可以增加為高優先順序請求提供服務的 PriorityLevelConfiguration 的 NominalConcurrencyShares。或者,對於 1.26 及更高版本,您可以增加競爭優先順序層級的 LendablePercent,以便給定的優先順序層級可以借用更多的席位池。
隔離非必要的請求,避免其耗盡其他流程的資源
為了請求隔離,您可以建立一個 FlowSchema,其主體與發出這些請求的使用者匹配,或者建立一個 FlowSchema,使其與請求的內容(對應於 resourceRules)匹配。接下來,您可以將此 FlowSchema 對應到具有低席位份額的 PriorityLevelConfiguration。
例如,假設來自預設命名空間中 Pod 的 list event 請求每個使用 10 個席位並執行 1 分鐘。為了防止這些昂貴的請求影響來自其他使用現有 service-accounts FlowSchema 的 Pod 的請求,您可以套用以下 FlowSchema 來隔離這些 list 呼叫與其他請求。
用於隔離 list event 請求的 FlowSchema 物件範例
apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
name: list-events-default-service-account
spec:
distinguisherMethod:
type: ByUser
matchingPrecedence: 8000
priorityLevelConfiguration:
name: catch-all
rules:
- resourceRules:
- apiGroups:
- '*'
namespaces:
- default
resources:
- events
verbs:
- list
subjects:
- kind: ServiceAccount
serviceAccount:
name: default
namespace: default
- 此 FlowSchema 捕獲預設命名空間中預設服務帳戶發出的所有 list event 呼叫。匹配優先順序 8000 低於現有 service-accounts FlowSchema 使用的值 9000,因此這些 list event 呼叫將匹配 list-events-default-service-account 而不是 service-accounts。
- catch-all PriorityLevelConfiguration 用於隔離這些請求。catch-all 優先順序層級具有非常小的並行份額,並且不會將請求排隊。
下一步
- 您可以造訪流量控制參考文件,以了解有關疑難排解的更多資訊。
- 有關 API 優先順序和公平性的設計細節的背景資訊,請參閱增強提案。
- 您可以透過 SIG API Machinery 或該功能的 slack 頻道提出建議和功能請求。