kube-apiserver限流機制原理

华为云开发者联盟發表於2024-04-07

本文分享自華為雲社群《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 
PriorityLevelConfiguration:解決老版本隔離性差的問題和優先順序問題,並定義了限流細節(總佇列數、佇列長度、是否可排隊)。當請求與某個FlowSchema匹配後,該請求會關聯FlowSchema中指定的PriorityLevelConfiguration資源,每個PriorityLevelConfiguration相互隔離,且能承受的併發請求數也不一樣
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處理過程

image.png

請求與叢集中的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規則,我們選擇一個檢視,如下圖:

image.png

下面我們建立新的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日誌資訊,見下圖:

image.png

迴圈操作deployment,我們可以使用命令檢視是否觸發限流等待

kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels

image.png
返回waitingRequests非0,則代表觸發最大併發數,有請求被限流進入等待佇列。PriorityLevelConfiguration資源不為空閒表示已達到併發上限

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章