使用ASM本地限流功能

更新时间: 2023-11-16 17:23:52

在大促等场景下,瞬间洪峰流量会使系统超出最大负载,调用大量堆积,导致整个调用链路卡死。ASM提供了本地限流功能,支持对网关和服务进行流量限制,达到保护系统的目的。本文介绍如何使用ASM本地限流功能。

前提条件

  • 已创建ASM实例,且ASM实例要符合以下要求:

    • 如果您使用的是ASM商业版(专业版),要求ASM商业版(专业版)为v1.11.5.30或以上版本。关于升级ASM实例的具体操作,请参见升级ASM实例

    • 如果您使用的是ASM标准版,ASM标准版仅支持Istio原生方式配置本地限流功能,且要求ASM标准版为v1.9或以上版本。不同Istio版本需参考相应版本文档,关于最新的Istio版本配置本地限流功能的具体操作,请参见Enabling Rate Limits using Envoy

  • 已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例

  • 已部署入口网关。具体操作,请参见创建入口网关

  • 已创建Bookinfo服务和Nginx。具体操作,请参见部署应用到ASM实例。本文将Bookinfo部署在default命名空间,将Nginx部署在foo命名空间。

  • 已创建ASM网关。具体操作,请参见创建入口网关

    展开查看Gateway YAML

    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: bookinfo-gateway
      namespace: default
    spec:
      selector:
        istio: ingressgateway
      servers:
      - hosts:
        - bf2.example.com
        port:
          name: http
          number: 80
          protocol: http
  • 已创建虚拟服务。具体操作,请参见管理虚拟服务

    展开查看VirtualService YAML

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: bookinfo
      namespace: default
    spec:
      gateways:
      - bookinfo-gateway
      hosts:
      - bf2.example.com
      http:
      - match:
        - uri:
            exact: /productpage
        - uri:
            prefix: /static
        - uri:
            exact: /login
        - uri:
            exact: /logout
        - uri:
            prefix: /api/v1/products
        name: productpage-route-name1
        route:
        - destination:
            host: productpage
            port:
              number: 9080
      - match:
        - uri:
            prefix: /nginx
        name: nginx-route-name1
        rewrite:
          uri: /
        route:
        - destination:
            host: nginx.foo.svc.cluster.local
            port:
              number: 80
  • 已安装流量加压工具。具体操作,请参见hey

适用对象

ASM本地限流功能适用于ASM网关和应用服务(注入了Sidecar)。

说明

您可以单击文件,直接下载本场景示例涉及的配置文件。

场景示例说明

本文以Bookinfo和Nginx为例介绍网关和服务限流的具体使用场景。Nginx将单独部署在foo命名空间,用于验证限流的开启范围。场景示例

网关限流

对网关进行限流,从流量入口处进行限流,防止下游服务被压垮。

使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源。然后使用以下内容,创建ASMLocalRateLimiter。

说明

以下配置中的limite.quota只针对单个网关实例生效,若网关有n个实例,test1该路由对应的后端服务限流阈值则为n * quota,若调整了后端服务实例个数,需要对应调整限流阈值。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMLocalRateLimiter
metadata:
  name: for-api-test
  namespace: default
spec:
  workloadSelector:
    labels:
      app: istio-ingressgateway
  isGateway: true
  configs:
    - match:
        vhost:
          name: "www.example1.com"   # 如果gateway中配置了多个host域名,填最后一个即可。
          port: 80
          route:
            name_match: "test1"   # VirtualService路由配置中对应route的name,若VirtualService路由配置下没有对应name的路由,则不生效。
      limit:
         fill_interval:
            seconds: 1
         quota: 10
    - match:
        vhost:
          name: "www.example2.com"
          port: 80
          route:
            name_match: "test1"
      limit:
         fill_interval:
            seconds: 1
         quota: 100

部分字段说明如下。关于字段的更多信息,请参见ASMLocalRateLimiter CRD说明

  • workloadSelector:用于匹配生效的Pod。本文为了使ASMLocalRateLimiter作用于网关,设置为istio-ingressgateway

  • isGateway:是否作用于网关,本示例设置为true

  • fill_interval下的seconds:令牌填充时间。

  • quota:令牌发放个数。本文设置seconds1quota100,表示1s内发放100个令牌,即网关1s内最多处理100个请求。

网关限流场景示例

场景一:对单个接口配置限流规则

bf2.example.com:80这个VirtualHost下的productpage-route-name1路由设定限流配置,使得访问productpage-route-name1路由下的/productpage/static/login/logout接口都将受到流量限制。

  1. 使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源

  2. 创建ASMLocalRateLimiter。

    1. 使用以下内容,创建asmlocalratelimiter-test-gw.yaml

      ASM版本为1.13.4以下

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMLocalRateLimiter
      metadata:
        name: ingressgateway
        namespace: istio-system
      spec:
        workloadSelector:
          labels:
            app: istio-ingressgateway
        isGateway: true
        configs:
        - limit:
            fill_interval:
              seconds: 1
            quota: 10
          match:
            vhost:
              name: bf2.example.com
              port: 80
              route:
                name_match: productpage-route-name1  # 该名称需要和VirtualService下的route name一致。

      ASM版本为1.13.4及以上

      您可以自定义限流返回的Header和Body内容,在limit下配置custom_response_body即可。

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMLocalRateLimiter
      metadata:
        name: ingressgateway
        namespace: istio-system
      spec:
        workloadSelector:
          labels:
            app: istio-ingressgateway
        isGateway: true
        configs:
        - limit:
            fill_interval:
              seconds: 1
            quota: 10
            custom_response_body: '{"ret_code": xxx, "message": "Your request be limited" }'
          match:
            vhost:
              name: bf2.example.com
              port: 80
              route:
                name_match: productpage-route-name1  # 该名称需要和virtualservice下的route name一致。
    2. 执行以下命令,创建ASMLocalRateLimiter。

      kubectl apply -f asmlocalratelimiter-test-gw.yaml
  3. 在hey工具中执行以下命令,持续产生压力流量。

    hey -host bf2.example.com -c 10 -n 100000 http://<ASM网关IP>/productpage
    hey -host bf2.example.com -c 10 -n 100000 http://<ASM网关IP>/nginx
  4. 执行以下命令,访问Bookinfo服务的/productpage接口。

    curl -H 'host: bf2.example.com'  http://<ASM网关IP>/productpage -v

    预期输出:

    < HTTP/1.1 429 Too Many Requests
    < Content-Length: 18
    < Content-Type: text/plain
    < Date: Thu, 13 Jan 2022 03:03:09 GMT
    < Server: istio-envoy
    <
    local_rate_limited

    可以看到访问Bookinfo服务受到限流。

  5. 执行以下命令,访问Bookinfo服务的/nginx接口。

    curl -H 'host: bf2.example.com'  http://${ASM_GATEWAY_IP}/nginx  -v

    返回结果中没有429,说明访问未限流。

场景二:对网关域名和端口的全局配置限流规则

bf2.example.com:80这个virtualHost设定限流配置,使得访问Bookinfo服务下的/productpage/static/login/logout/nginx接口都将受到流量限制。

  1. 使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源

  2. 创建ASMLocalRateLimiter。

    1. 使用以下内容,创建asmlocalratelimiter-test-gw-global.yaml

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMLocalRateLimiter
      metadata:
        name: ingressgateway
        namespace: istio-system
      spec:
        workloadSelector:
          labels:
            app: istio-ingressgateway
        isGateway: true
        configs:
          - match:
              vhost:
                name: "bf2.example.com"
                port: 80
            limit:
               fill_interval:
                  seconds: 1
               quota: 10
    2. 执行以下命令,创建ASMLocalRateLimiter。

      kubectl apply -f asmlocalratelimiter-test-gw-global.yaml
  3. 在hey工具中执行以下命令,持续产生压力流量。

    hey -host bf2.example.com -c 10 -n 100000 http://${ASM_GATEWAY_IP}/nginx
  4. 执行以下命令,访问Bookinfo服务的/nginx接口。

    curl -H 'host: bf2.example.com'  http://${ASM_GATEWAY_IP}/nginx -v

    可以看到,返回HTTP/1.1 429 Too Many Requests,说明访问Bookinfo服务的/nginx接口受到限流。

场景三:删除限流配置后,访问恢复

  1. 使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源

  2. 执行以下命令,删除限流配置文件。

    kubectl delete -f asmlocalratelimiter-test-gw.yaml
    kubectl delete -f asmlocalratelimiter-test-gw-global.yaml
  3. 执行以下命令,访问Bookinfo服务的/nginx接口。

    curl -H 'host: bf2.example.com'  http://${ASM_GATEWAY_IP}/nginx -v

    返回结果中没有429,说明访问未限流。

应用服务限流

对服务进行限流,限制服务一定时间内处理请求的数量。

使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源。然后使用以下内容,创建ASMLocalRateLimiter。

说明

针对应用服务进行配置,若服务工作负载有n个实例,对应整体服务限流阈值为n * quota_per_instance。

apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMLocalRateLimiter
metadata:
  name: reviews-v3-local-ratelimiter
  namespace: default
spec:
  workloadSelector:
    labels:
      app: reviews
      version: v3
....

若服务有多个版本,可以通过WorkLoadSelector label定义生效的Deployment范围,例如以上表示仅针对reviews的v3版本配置限流。

应用服务限流场景示例

重要

应用服务限流生效前提是应用服务已注入Sidecar。在操作应用服务限流配置之前,请务必移除网关相关限流配置,避免对应用服务限流配置产生影响。

场景一:对reviews服务配置限流规则

  1. 使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源

  2. 创建ASMLocalRateLimiter。

    1. 使用以下内容,创建asmlocalratelimiter-test-reviews.yaml

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMLocalRateLimiter
      metadata:
        name: reviews
        namespace: default
      spec:
        workloadSelector:
          labels:
            app: reviews
        configs:
          - match:
              vhost:
                name: "*"
                port: 9080
                route:
                  header_match:
                  - name: ":path"
                    prefix_match: "/"
            limit:
               fill_interval:
                  seconds: 1
               quota: 10

      以上配置是针对reviews服务的9080端口,然后通过header_match配置匹配条件,匹配以/开头的请求。

    2. 执行以下命令,创建ASMLocalRateLimiter。

      kubectl apply -f asmlocalratelimiter-test-reviews.yaml
  3. 在hey工具中执行以下命令,持续产生压力流量。

    hey -host bf2.example.com -c 10 -n 100000 http://<ASM网关IP>/productpage
  4. 执行以下命令,查看productpage sidecar日志。

    kubectl logs -f productpage-v1-b84f8bfdd-wgxlc  -c istio-proxy

    预期输出:

    [2022-01-14T07:56:13.086Z] "GET /reviews/0 HTTP/1.1" 429 - via_upstream - "-" 0 18 1 1 "-" "hey/0.0.1" "9295da56-9a6b-9476-b662-1cbd61a82898" "reviews:9080" "10.180.0.190:9080" outbound|9080|v1|reviews.default.svc.cluster.local 10.180.0.196:36702 192.168.195.113:9080 10.180.0.196:33522 - -
    [2022-01-14T07:56:13.091Z] "GET /reviews/0 HTTP/1.1" 429 - via_upstream - "-" 0 18 0 0 "-" "hey/0.0.1" "9295da56-9a6b-9476-b662-1cbd61a82898" "reviews:9080" "10.180.0.190:9080" outbound|9080|v1|reviews.default.svc.cluster.local 10.180.0.196:36702 192.168.195.113:9080 10.180.0.196:33528 - -
    [2022-01-14T07:56:13.051Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 41 1 "-" "hey/0.0.1" "061d3542-52a7-9511-b217-7fdf9ee9a1dd" "details:9080" "10.180.0.160:9080" outbound|9080||details.default.svc.cluster.local 10.180.0.196:58724 192.168.127.75:9080 10.180.0.196:57754 - default
    [2022-01-14T07:56:13.095Z] "GET /reviews/0 HTTP/1.1" 429 - via_upstream - "-" 0 18 0 0 "-" "hey/0.0.1" "061d3542-52a7-9511-b217-7fdf9ee9a1dd" "reviews:9080" "10.180.0.190:9080" outbound|9080|v1|reviews.default.svc.cluster.local 10.180.0.196:36702 192.168.195.113:9080 10.180.0.196:33534 - -

    可以看到访问reviews:9080返回结果中包含429,说明访问受到限流。

场景二:对review v3版本配置限流规则

  1. 使用kubectl连接ASM,具体操作,请参见通过控制面kubectl访问Istio资源

  2. 创建ASMLocalRateLimiter。

    1. 使用以下内容,创建asmlocalratelimiter-test-reviews-only-v3.yaml。

      apiVersion: istio.alibabacloud.com/v1beta1
      kind: ASMLocalRateLimiter
      metadata:
        name: reviews
        namespace: default
      spec:
        workloadSelector:
          labels:
            app: reviews
            version: v3
        configs:
          - match:
              vhost:
                name: "*"
                port: 9080
                route:
                  header_match:
                  - name: ":path"
                    prefix_match: "/"
            limit:
               fill_interval:
                  seconds: 1
               quota: 10

      以上配置是针对reviews v3服务的9080端口,然后通过header_match配置匹配条件,匹配/开头的请求。

    2. 执行以下命令,创建ASMLocalRateLimiter。

      kubectl apply -f asmlocalratelimiter-test-reviews-only-v3.yaml
  3. 在hey工具中执行以下命令,持续产生压力流量。

    hey -host bf2.example.com -c 10 -n 100000 http://<ASM网关IP>/productpage
  4. 执行以下命令,查看reviews-v1、reviews-v2、reviews-v3对应Pod下Sidecar的日志。

    kubectl logs -f ${your-reviews-pod-name}  -c istio-proxy

    可以看到只有reviews-v3下access_log日志对应请求的返回包含429,reviews-v2和reviews-v3对应请求的返回是正常的200。说明只有reviews-v3服务受到限流,reviews-v1和reviews-v2服务未受到限流。

相关文档

ASMLocalRateLimiter CRD说明

阿里云首页 服务网格 ASM 相关技术圈