本文分享自華為雲社群《kube-apiserver限流機制原理》,作者:可以交個朋友。
背景
apiserver是kubernetes中最重要的元件,一旦遇到惡意刷介面或請求量超過承載範圍,apiserver服務可能會崩潰,導致整個kubernetes叢集不可用。所以我們需要對apiserver做限流處理來提升kubernetes的健壯性。
k8s-apiserver限流能力發展過程
apiserver限流能力的發展分為兩個階段:
kubernetes 1.18版本之前kube-apiserver只是將請求分成了變更型別(create、update、delete、patch)和非變更型別(get、list、watch),並透過啟動引數設定了兩種型別的最大併發數。--max-requests-inflight ## 限制同時執行的非變更型別請求的個數上限,0表示無限制。 --max-mutating-requests-inflight ## 限制同時執行的變更型別請求的個數上限。0 表示無限制。
此時的apiserver限流能力較弱,若某個客戶端錯誤的向kube-apiserver發起大量的請求時,必然會阻塞kube-apiserver,影響其他客戶端的請求,因此高階的限流APF就誕生了。
kubernetes1.18版本之後APF( APIPriorityAndFairness )成為kubernetes的預設限流方式。 APF以更細粒度的方式對請求進行分類和隔離,根據優先順序和公平性進行處理。--enable-priority-and-fairness ## 該值作為APF特性開關,預設為true
--max-requests-inflight、--max-mutating-requests-inflight ## 當開啟APF時,倆值相加確定kube-apiserver的總併發上限
兩個階段限流能力對比
限流能力 | 1.18版本前 | 1.18版本後(APF) |
---|---|---|
顆粒度 | 僅根據是否變更做分類 | 可以根據請求物件、請求者身份、名稱空間等做分類 |
隔離性 | 一個壞使用者可能堵塞整個系統 | 為請求分配固定佇列,壞請求只能撐爆其使用的佇列 |
公平性 | 會出現餓死 | 用公平性演算法從佇列中取出請求 |
優先順序 | 無 | 有特權級別,可讓重要請求不被限制 |
APF關鍵資源介紹
APF透過FlowSchema 和 PriorityLevelConfiguration兩個資源配置限流策略。
FlowSchema:解決老版本分類顆粒度粗的問題。根據rules欄位匹配請求,匹配規則包含:請求物件、執行操作、請求者身份和名稱空間apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 kind: FlowSchema # 一個kubernetes叢集中可以定義多個FlowSchema metadata: name: myfl spec: distinguisherMethod: # 可選值為:ByNamespace或ByUser,用於把請求分組。屬於同組的請求會分配到固定的queue中,如果省略該引數,則該FlowSchema匹配的所有請求都將視為同一個分組。 type: ByUser matchingPrecedence: 90 # 數字越小代表FlowSchema的匹配順序越在前,取值範圍:1~10000。 priorityLevelConfiguration: # FlowSchema關聯的priorityLevelConfiguration name: mypl rules: - nonResourceRules: # 匹配非資源型:匹配介面URL - nonResourceURLs: - '*' resourceRules: # 匹配資源型:匹配apigroup、namespace、resources、verbs - apiGroups: - '*' namespaces: - '*' resources: - '*' verbs: - get - create - list - update subjects: # 匹配請求者主體:可選Group、User、ServiceAccount - group: name: '*' kind: Group - kind: User user: name: '*' - kind: ServiceAccount serviceAccount: name: myserviceaccount namespace: demo
apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 kind: PriorityLevelConfiguration ## 每個PriorityLevelConfiguration有自己獨立的限流配置, PriorityLevelConfiguration之間是完全隔離的。 metadata: name: mypl spec: type: Limited # 設定是否為特權級別,如果為Exempt則不進行限流,如果為Limited則進行限流 limited: assuredConcurrencyShares: 2 # 值越大,PriorityLevelConfiguration的併發上限越高。若當前併發執行數未達到併發上限,則PL處於空閒狀態。 limitResponse: # 定義如何處理當前無法被處理的請求 type: Queue # 型別,Queue或者Reject,Reject直接返回429並拒絕,Queue將請求加入佇列 queuing: handSize: 1 # 根據ByNamespace或ByUser對請求分組,每個分組對應queues的數量, queueLengthLimit: 20 # 此PriorityLevelConfiguration中每個佇列的長度 queues: 2 # 此PriorityLevelConfiguration中的佇列數
一個FlowSchema只能關聯一個priorityLevelConfiguration,多個FlowSchema可以關聯同一個priorityLevelConfiguration
PriorityLevelConfiguration併發上限 = assuredConcurrencyShares / 所有assuredConcurrencyShares之和 * apiserver總併發數APF處理過程
請求與叢集中的FlowSchema列表按照順序依次匹配,每個FlowSchema的matchingPrecedence欄位決定其在列表中的順序,matchingPrecedence欄位值越小,越靠前,越先進行匹配請求。
根據FlowSchema資源中的rules規則進行匹配,匹配方式可以是 “請求的資源型別”、“請求的動作型別”、“請求者的身份”、“請求的名稱空間” 等多個維度。
若請求與某個FlowSchema成功匹配,匹配就會結束。FlowSchema關聯著一個PriorityLevelConfiguration,每個PriorityLevelConfiguration中包含許多queue,根據FlowSchema.spec.Distinguisher欄位將請求進行"分組",根據分組來分配queue,分配queue數量由PriorityLevelConfiguration資源的handSize欄位決定,如果省略該引數,則該FlowSchema匹配的所有請求都將視為同一個"分組"。
每個PriorityLevelConfiguration資源都有獨立的併發上限,assuredConcurrencyShares欄位為apiserver總併發數的權重佔比,值越大分配的併發上限就越高,當PriorityLevelConfiguration達到併發上限後,請求會根據所屬的"分組"寫入固定的queue中,請求被阻塞等待。請求與queue的固定關聯可以讓惡意使用者隻影響其使用的queue,而不會影響同PriorityLevelConfiguration中的其他queue。
當PriorityLevelConfiguration未達到併發上限時,fair queuing演算法從所有queue中選擇一個合適的queue取出請求,解除請求的阻塞,執行這個請求。fair queuing演算法能保證同一個 PriorityLevelConfiguration 中的所有queue被處理機會平等。
APF實戰
kubernetes原生自帶了一些FlowSchema和PriorityLevelConfiguration規則,我們選擇一個檢視,如下圖:
下面我們建立新的APF規則:當請求物件是apf名稱空間中的deployment,則進行"apfpl"限流規則。
apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 kind: FlowSchema metadata: name: apffl spec: matchingPrecedence: 150 priorityLevelConfiguration: name: apfpl ## 關聯名為apfpl的PriorityLevelConfiguration rules: - resourceRules: - apiGroups: - apps clusterScope: true namespaces: - apf ## 匹配apf名稱空間 resources: - deployments ## 匹配操作deployment的請求 verbs: - '*' ## 匹配任意操作型別 subjects: - kind: Group group: name: '*' ## 匹配任意組身份 --- apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 kind: PriorityLevelConfiguration metadata: name: apfpl spec: limited: assuredConcurrencyShares: 2 limitResponse: ## 設定限流處理細節 queuing: handSize: 1 queueLengthLimit: 20 queues: 2 type: Queue type: Limited ## 對請求做限流處理
接著在apf名稱空間和default名稱空間分別建立deployment進行測試。apf_fs為請求被分類到的 FlowSchema 的名稱,apf_pl為該請求的優先順序名稱。檢視apiserver日誌資訊,見下圖:
迴圈操作deployment,我們可以使用命令檢視是否觸發限流等待
kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
返回waitingRequests非0,則代表觸發最大併發數,有請求被限流進入等待佇列。PriorityLevelConfiguration資源不為空閒表示已達到併發上限
點選關注,第一時間瞭解華為雲新鮮技術~