1. 問題起源
在kubernetes里,使用kubectl get pods 時,返回
I0508 05:43:04.655602 ?100742 request.go:668] Waited for 1.178494016s due to client-side?throttling, not priority and fairness, request: GET:https://10.103.0.1:443/apis/cert-manager.io/v1?timeout=32s
其中的URL每次會變。
2. 原因探究
(1) kubectl 是一個go語言實現的工具,其核心功能是發一下rest API請求到kubernetes,并顯示返回的結果.
比如?
hw2v2z3:# kubectl version
Client Version: v1.30.2+rke2r1
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.30.2+rke2r1
?
其中Client Verion就是kubectl這個命令本身的版本,而Server Version是kubernetes的版本,也就API server的版本.
(2) 什么是client-side?throttling
回到問題本身,當執行kubect get 命令時,返回的是"client-side?throttling",此處的client-side 即是kubectl 命令本身。也就是說,kubectl 發送了太多的rest API請求,結果kubectl 自身就發現命令太多而觸發了流控,所以提示?"client-side?throttling"
(3) 一條kubectl get 命令為啥會發多條REST API請求
The Kubernetes Discovery Cache: Blessing and Curse · Jonny Langefeld
kubernetes在設計時就提供了非常靈活的API接口。 一般來說我們會理解為kubectl get pod對應的api是GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?limit=500,但kubernetes設計時認為這條API中的所有字段都是要查詢過來的。比如v1, namespace, pods這些關鍵詞都是通過一系列的API請求查詢到有這些資源,這個過程稱為Discovery,最終才會生成一條API請求獲取你真正要查詢 的POD。
還有一關鍵點,就是kubernetes中CRD會大大增加要查詢的資源數量。我的理解是一個CRD會觸發多條的查詢資源命令,而且是不同的URL。這也可以解釋為什么出現throttlin時,URL總是不同的原因。所以當出現這個錯誤時,首先需要查詢系統中是不是有很多(>100)個CRD.
如果您覺得這個解釋還是不清晰,可以看上面的貼子,看看文章中說的100s描述的API請求.
當然,這么多查詢的結果會緩存下來,在~/.kube/cache/discovery/<host>/v1/serverresources.json
(4)為什么會一直有"client-side throttling"錯誤
按照第(3)節的描述,獲取到的各種配置是有緩存的,也就是一次次get各種資源(如v1, namespace, pod),匯總起來總是可以收齊的。那為啥會老失敗呢?
因為這個緩存是有有效期的,默認10分鐘。也就是10分鐘后,kubectl命令又會觸發再重新取一遍所有的資源。那這樣又會從頭再來,一遍遍的失敗。因為觸發了流控,我們也不知道多少次獲取后,才能獲取到所有資源。
3. 源碼佐證
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/rest/request.go里的tryThrottleWithInfo:
if latency > longThrottleLatency {
? ? ? ? if retryInfo == "" {
? ? ? ? ? ? retryInfo = "client-side throttling, not priority and fairness"
? ? ? ? }
另外,下面這個PR是把Discovery Burst請求從100改到300
https://github.com/kubernetes/kubernetes/pull/109141/files
本文主要記錄碰到throttling的過程,不一定能解決問題,但是一定可以知道問題的原因. That's help.