全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用ASMGlobalRateLimiter對應用服務入口流量配置全域限流

更新時間:Sep 12, 2024

限流是一種限制發送到服務端的請求數量的機制。它指定用戶端在給定時間段內可以向服務端發送的最大請求數,通常表示為一段時間內的請求數,例如每分鐘300個請求或每秒10個請求等。服務網格ASM自1.18.0.131版本起,支援針對入口網關和注入了Sidecar的應用服務的入口流量配置全域限流。本文介紹如何在ASM中使用ASMGlobalRateLimiter對應用服務入口流量配置全域限流。

前提條件

部署限流服務

您需要先在資料面叢集中部署限流服務,才能使全域限流功能生效。部署限流服務和樣本應用的步驟如下。

說明

Envoy代理實現限流主要有兩種方式:全域限流、本地限流。本文僅介紹全域限流的配置方法。關於限流的相關概念以及如何配置本地限流,請參見在流量管理中心配置本地限流

  1. 使用以下內容,建立ratelimit-svc.yaml。

    展開查看ratelimit-svc.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: redis
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: redis
      labels:
        app: redis
    spec:
      ports:
      - name: redis
        port: 6379
      selector:
        app: redis
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
      template:
       metadata:
          labels:
            app: redis
            sidecar.istio.io/inject: "false"
       spec:
          containers:
          - image: redis:alpine
            imagePullPolicy: Always
            name: redis
            ports:
            - name: redis
              containerPort: 6379
          restartPolicy: Always
          serviceAccountName: redis
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ratelimit-config
    data:
      config.yaml: |
        {}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: ratelimit
      labels:
        app: ratelimit
    spec:
      ports:
      - name: http-port
        port: 8080
        targetPort: 8080
        protocol: TCP
      - name: grpc-port
        port: 8081
        targetPort: 8081
        protocol: TCP
      - name: http-debug
        port: 6070
        targetPort: 6070
        protocol: TCP
      selector:
        app: ratelimit
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ratelimit
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ratelimit
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: ratelimit
            sidecar.istio.io/inject: "false"
        spec:
          containers:
            # Latest image from https://hub.docker.com/r/envoyproxy/ratelimit/tags
          - image: envoyproxy/ratelimit:e059638d 
            imagePullPolicy: Always
            name: ratelimit
            command: ["/bin/ratelimit"]
            env:
            - name: LOG_LEVEL
              value: debug
            - name: REDIS_SOCKET_TYPE
              value: tcp
            - name: REDIS_URL
              value: redis:6379
            - name: USE_STATSD
              value: "false"
            - name: RUNTIME_ROOT
              value: /data
            - name: RUNTIME_SUBDIRECTORY
              value: ratelimit
            - name: RUNTIME_WATCH_ROOT
              value: "false"
            - name: RUNTIME_IGNOREDOTFILES
              value: "true"
            ports:
            - containerPort: 8080
            - containerPort: 8081
            - containerPort: 6070
            volumeMounts:
            - name: config-volume
              # $RUNTIME_ROOT/$RUNTIME_SUBDIRECTORY/$RUNTIME_APPDIRECTORY/config.yaml
              mountPath: /data/ratelimit/config
          volumes:
          - name: config-volume
            configMap:
              name: ratelimit-config
  2. 在ACK叢集對應的KubeConfig環境下,執行以下命令,在叢集中建立限流服務和限流服務依賴的Redis服務。

    kubectl apply -f ratelimit-svc.yaml

情境一:對服務的特定連接埠配置全域限流

對httpbin服務的8000連接埠進行限流。配置限流規則後,發往httpbin服務8000連接埠的所有請求都將受到流量速率限制。

  1. 使用以下內容,建立global-ratelimit-svc.yaml。

    展開查看global-ratelimit-svc.yaml

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMGlobalRateLimiter
    metadata:
      name: global-svc-test
      namespace: default
    spec:
      workloadSelector:
        labels:
          app: httpbin
      rateLimitService:
        host: ratelimit.default.svc.cluster.local
        port: 8081
        timeout:
          seconds: 5
      isGateway: false
      configs:
      - name: httpbin
        limit:
          unit: MINUTE
          quota: 1
        match:
          vhost:
            name: '*'
            port: 8000

    部分欄位說明如下。關於欄位的更多資訊,請參見ASMGlobalRateLimiter CRD說明

    欄位

    說明

    workloadSelector

    用於匹配限流生效的工作負載。本情境中全域限流生效於httpbin服務的工作負載,設定為app: httpbin

    isGateway

    是否作用於網關。本樣本中設定為false

    rateLimitService

    限流服務的網域名稱、連接埠和連線逾時設定。根據情境一:對服務的特定連接埠配置全域限流中部署的限流服務,配置如下:

        host: ratelimit.default.svc.cluster.local
        port: 8081
        timeout:
          seconds: 5

    limit

    需要生效的限流配置參數。其中unit表示限流檢測的時間單位,quota表示單位時間內允許的請求總量。

    本樣本配置unitMINUTEquota1,表示匹配路由上每分鐘只能發送一個請求,超出的請求將被限流。

    vhost

    限流匹配的網域名稱和路由項配置。在生效於應用服務時,name需要填寫為'*'port需要填寫為服務的Service連接埠。

  2. 在ASM執行個體對應的KubeConfig環境下,執行以下命令,建立生效於應用服務httpbin入口流量的全域限流規則。

    kubectl apply -f global-ratelimit-svc.yaml
  3. 執行以下命令,擷取調諧完成的全域限流規則配置內容。

    kubectl get asmglobalratelimiter global-svc-test -o yaml

    展開查看預期輸出

    apiVersion: istio.alibabacloud.com/v1
    kind: ASMGlobalRateLimiter
    metadata:
      name: global-svc-test
      namespace: default
    spec:
      configs:
      - limit:
          quota: 1
          unit: MINUTE
        match:
          vhost:
            name: '*'
            port: 8000
        name: httpbin
      isGateway: false
      rateLimitService:
        host: ratelimit.default.svc.cluster.local
        port: 8081
        timeout:
          seconds: 5
      workloadSelector:
        labels:
          app: httpbin
    status:
      config.yaml: |
        descriptors:
        - key: generic_key
          rate_limit:
            requests_per_unit: 1
            unit: MINUTE
          value: RateLimit[global-svc-test.default]-Id[3833670472]
        domain: ratelimit.default.svc.cluster.local
      message: ok
      status: successful
  4. 將上一步預期輸出的ASMGlobalRateLimiter資源中status欄位的config.yaml內容,粘貼至ratelimit-config.yaml,產生全域限流服務配置。

    ASMGlobalRateLimiter中status欄位下的config.yaml欄位中的字串內容,需原樣粘貼至ConfigMap中data中的同名config.yaml欄位中。

    展開查看ratelimit-config.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ratelimit-config
    data:
      config.yaml: |
        descriptors:
        - key: header_match
          rate_limit:
            requests_per_unit: 1
            unit: MINUTE
          value: RateLimit[global-svc-test.default]-Id[1492204717]
        domain: ratelimit.default.svc.cluster.local
  5. 在ACK叢集對應的KubeConfig環境下,執行以下命令,在叢集中更新全域限流服務配置。

    kubectl apply -f ratelimit-config.yaml
  6. 執行以下命令,進入sleep應用開啟bash。

    kubectl exec -it deploy/sleep -- sh
  7. 執行以下命令,連續訪問httpbin服務兩次。

    curl httpbin:8000/get -v
    curl httpbin:8000/get -v

    預期輸出:

    < HTTP/1.1 429
    < x-envoy-ratelimited: true
    < x-ratelimit-limit: 1, 1;w=60
    < x-ratelimit-remaining: 0
    < x-ratelimit-reset: 5
    < date: Thu, 26 Oct 2023 04:23:54 GMT
    < server: envoy
    < content-length: 0
    < x-envoy-upstream-service-time: 2
    < 
    * Connection #0 to host httpbin left intact

    在全域限流配置中,限制1分鐘之內只能有一次訪問httpbin服務的請求。當連續兩次訪問httpbin服務時,可以看到第二條請求被限流,表明對注入Sidecar的應用服務入口流量配置全域限流成功。

情境二:在服務特定連接埠上,針對發往指定路徑的請求進行限流

對httpbin服務的8000連接埠進行限流,並限制限流只生效在訪問/headers路徑的請求上。配置限流規則後,發往httpbin服務8000連接埠、且訪問路徑/headers的所有請求都將受到流量速率限制。

  1. 根據ASM版本,按需選擇以下內容,建立global-ratelimit-svc.yaml。

    • ASM版本為1.19.0以下:

      展開查看YAML

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMGlobalRateLimiter
      metadata:
        name: global-svc-test
        namespace: default
      spec:
        workloadSelector:
          labels:
            app: httpbin
        rateLimitService:
          host: ratelimit.default.svc.cluster.local
          port: 8081
          timeout:
            seconds: 5
        isGateway: false
        configs:
        - name: httpbin
          limit:
            unit: MINUTE
            quota: 1
          match:
            vhost:
              name: '*'
              port: 8000
              route:
                header_match:
                - name: ":path"
                  prefix_match: "/headers"
    • ASM版本為1.19.0及以上:

      展開查看YAML

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMGlobalRateLimiter
      metadata:
        name: global-svc-test
        namespace: default
      spec:
        workloadSelector:
          labels:
            app: httpbin
        rateLimitService:
          host: ratelimit.default.svc.cluster.local
          port: 8081
          timeout:
            seconds: 5
        isGateway: false
        configs:
        - name: httpbin
          limit:
            unit: SECOND
            quota: 100000
          match:
            vhost:
              name: '*'
              port: 8000
          limit_overrides:
          - request_match:
              header_match:
              - name: ":path"
                prefix_match: "/headers"
            limit:
              unit: MINUTE
              quota: 1

      部分欄位說明如下。關於欄位的更多資訊,請參見ASMGlobalRateLimiter CRD說明

      欄位

      說明

      workloadSelector

      用於匹配限流生效的工作負載。本情境中全域限流生效於httpbin服務的工作負載,設定為app: httpbin

      isGateway

      是否作用於網關。本樣本設定為false

      rateLimitService

      限流服務的網域名稱、連接埠和連線逾時設定。根據情境二:在服務特定連接埠上,針對發往指定路徑的請求進行限流中部署的限流服務,配置如下:

          host: ratelimit.default.svc.cluster.local
          port: 8081
          timeout:
            seconds: 5

      limit

      需要生效的限流配置參數。其中unit表示限流檢測的時間單位,quota表示單位時間內允許的請求總量。

      本樣本配置unitMINUTEquota1,表示匹配路由上每分鐘只能發送一個請求,超出的請求將被限流。

      在ASM執行個體為1.19.0及以上版本,限流配置參數為每秒100000個請求,約等於沒有限流,因為針對滿足特定條件請求的限流生效在limit_overrides欄位中。

      vhost

      限流匹配的網域名稱和路由項配置。在生效於應用服務時,name需要填寫為'*'port需要填寫為服務的Service連接埠。

      • 在ASM執行個體為1.19.0以下版本,您還可以在route中配置針對請求的Header匹配規則。本樣本中匹配名為:path的特殊Header,即匹配請求的路徑,語義為匹配所有路徑以/開頭的請求。

      • 在ASM執行個體為1.19.0及以上版本,在route中配置針對請求的Header匹配規則被移動到limit_overrides欄位中。

      limit_overrides

      限流覆蓋配置,僅支援ASM執行個體為1.19.0及以上版本。支援匹配請求的不同屬性,並對匹配到的特定請求應用單獨的限流配置。在本樣本中,limit_overrides欄位裡指定了匹配特殊的Header :path,即匹配請求的路徑,語義為匹配所有路徑以/headers開頭的請求。

  2. 在ASM執行個體對應的KubeConfig環境下,執行以下命令,建立生效於應用服務httpbin入口流量的全域限流規則。

    kubectl apply -f global-ratelimit-svc.yaml
  3. 執行以下命令,擷取調諧完成的全域限流規則配置內容。

    kubectl get asmglobalratelimiter global-svc-test -o yaml

    展開查看預期輸出

    apiVersion: istio.alibabacloud.com/v1
    kind: ASMGlobalRateLimiter
    metadata:
      name: global-svc-test
      namespace: default
    spec:
      configs:
      - limit:
          quota: 100000
          unit: SECOND
        limit_overrides:
        - limit:
            quota: 1
            unit: MINUTE
          request_match:
            header_match:
            - name: :path
              prefix_match: /headers
        match:
          vhost:
            name: '*'
            port: 8000
        name: httpbin
      isGateway: false
      rateLimitService:
        host: ratelimit.default.svc.cluster.local
        port: 8081
        timeout:
          seconds: 5
      workloadSelector:
        labels:
          app: httpbin
    status:
      config.yaml: |
        descriptors:
        - descriptors:
          - key: header_match
            rate_limit:
              requests_per_unit: 1
              unit: MINUTE
            value: RateLimit[global-svc-test.default]-Id[2613586978]
          key: generic_key
          rate_limit:
            requests_per_unit: 100000
            unit: SECOND
          value: RateLimit[global-svc-test.default]-Id[2613586978]
        domain: ratelimit.default.svc.cluster.local
      message: ok
      status: successful
  4. 將上一步預期輸出的ASMGlobalRateLimiter資源中status欄位的config.yaml內容,粘貼至ratelimit-config.yaml,產生全域限流服務配置。

    ASMGlobalRateLimiter中status欄位下的config.yaml欄位中的字串內容,需原樣粘貼至ConfigMap中data中的同名config.yaml欄位中。

    展開查看ratelimit-config.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ratelimit-config
    data:
      config.yaml: |
        descriptors:
        - descriptors:
          - key: header_match
            rate_limit:
              requests_per_unit: 1
              unit: MINUTE
            value: RateLimit[global-svc-test.default]-Id[2613586978]
          key: generic_key
          rate_limit:
            requests_per_unit: 100000
            unit: SECOND
          value: RateLimit[global-svc-test.default]-Id[2613586978]
        domain: ratelimit.default.svc.cluster.local
  5. 在ACK叢集對應的KubeConfig環境下,執行以下命令,在叢集中更新全域限流服務配置。

    kubectl apply -f ratelimit-config.yaml
  6. 執行以下命令,進入sleep應用開啟bash。

    kubectl exec -it deploy/sleep -- sh
  7. 執行以下命令,連續訪問httpbin服務的/headers路徑兩次。

    curl httpbin:8000/headers -v
    curl httpbin:8000/headers -v

    預期輸出:

    < HTTP/1.1 429 Too Many Requests
    < x-envoy-ratelimited: true
    < x-ratelimit-limit: 1, 1;w=60
    < x-ratelimit-remaining: 0
    < x-ratelimit-reset: 5
    < date: Thu, 26 Oct 2023 04:23:54 GMT
    < server: envoy
    < content-length: 0
    < x-envoy-upstream-service-time: 2
    < 
    * Connection #0 to host httpbin left intact

    在全域限流配置中,限制在/headers路徑上,1分鐘之內只能有一次訪問httpbin服務的請求。當連續兩次訪問httpbin服務的/headers路徑時,可以看到第二條請求被限流,表明對注入Sidecar的應用服務入口流量配置全域限流成功。

  8. 執行以下命令,訪問httpbin服務的/get路徑。

    curl httpbin:8000/get -v

    展開查看預期輸出

    *   Trying 192.168.243.21:8000...
    * Connected to httpbin (192.168.243.21) port 8000 (#0)
    > GET /get HTTP/1.1
    > Host: httpbin:8000
    > User-Agent: curl/8.1.2
    > Accept: */*
    >
    < HTTP/1.1 200 OK
    < server: envoy
    < date: Thu, 11 Jan 2024 06:25:09 GMT
    < content-type: application/json
    < content-length: 431
    < access-control-allow-origin: *
    < access-control-allow-credentials: true
    < x-envoy-upstream-service-time: 7
    <
    {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Host": "httpbin:8000",
        "User-Agent": "curl/8.1.2",
        "X-Envoy-Attempt-Count": "1",
        "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=be10819991ba1a354a89e68b3bed1553c12a4fba8b65fbe0f16299d552680b29;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
      },
      "origin": "127.0.0.6",
      "url": "http://httpbin:8000/get"
    }
    * Connection #0 to host httpbin left intact

    可以看到發往httpbin服務其它路徑的請求並未受到全域限流配置的影響,仍然可以正常訪問。

相關操作

查看全域限流相關指標

全域限流會產生以下指標:

指標

指標類型

描述

envoy_cluster_ratelimit_ok

Counter

被全域限流服務允許存取的請求總數

envoy_cluster_ratelimit_over_limit

Counter

被全域限流服務判定為觸發限流的請求總數

envoy_cluster_ratelimit_error

Counter

調用全域限流服務失敗的請求總數

您可以通過配置Sidecar代理的proxyStatsMatcher使Sidecar代理上報相關指標,然後使用Prometheus採集並查看限流相關指標。

  1. 通過proxyStatsMatcher配置Sidecar代理上報限流指標。在配置proxyStatsMatcher時,選中正則匹配,配置為.*ratelimit.*。具體操作,請參見proxyStatsMatcher

  2. 重新部署httpbin服務。具體操作,請參見重新部署工作負載

  3. 參照情境一在流量管理中心配置本地限流,完成本地限流配置及請求訪問。

  4. 執行以下命令,查看httpbin服務的全域限流相關指標。

    kubectl exec -it deploy/httpbin -c istio-proxy -- curl localhost:15090/stats/prometheus|grep envoy_cluster_ratelimit

    預期輸出:

    # TYPE envoy_cluster_ratelimit_ok counter
    envoy_cluster_ratelimit_ok{cluster_name="inbound|80||"} 904
    # TYPE envoy_cluster_ratelimit_over_limit counter
    envoy_cluster_ratelimit_over_limit{cluster_name="inbound|80||"} 3223

配置全域限流指標採集和警示

您可以配置Prometheus執行個體採集網格代理暴露的全域限流相關指標,並基於關鍵計量配置警示規則,實現限流發生時的及時警示。本文以可觀測監控Prometheus版為例說明如何配置全域限流指標採集和警示。

  1. 在可觀測監控Prometheus版中,為資料面叢集接入阿里雲ASM組件或升級至最新版,以保證可觀測監控Prometheus版可以採集到暴露的全域限流指標。關於接入組件的具體操作,請參見接入組件管理。(如果您已經整合自建Prometheus實現網格監控來採集服務網格指標,則無需做額外操作。)

  2. 建立針對全域限流的警示規則。具體操作,請參見通過自訂PromQL建立Prometheus警示規則。配置警示規則的關鍵參數的填寫樣本如下,其餘參數可參考上述文檔根據實際需求填寫。

    參數

    樣本

    說明

    自訂PromQL語句

    (sum by(namespace, service_istio_io_canonical_name) (increase(envoy_cluster_ratelimit_over_limit[1m]))) > 0

    通過increase查詢最近1分鐘之內被限流的請求數量,並根據觸發限流的服務所在命名空間以及服務名稱進行分組。當1分鐘內被限流的請求數量大於0時觸發警示。

    警示內容

    發生全域限流!命名空間:{{$labels.namespace}},觸發限流的服務:{{$labels.service_istio_io_canonical_name}}。當前1分鐘內被限流的請求數量:{{ $value }}

    樣本的警示資訊展示了觸發限流的服務所在命名空間以及服務名稱,以及最近1分鐘內發往該服務被限流的請求數量。

相關文檔