kube-apiserver限流機制原理

本文分享自華爲雲社區《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資源不爲空閒表示已達到併發上限

 

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章