在大促等场景下,瞬间洪峰流量会使系统超出最大负载,调用大量堆积,导致整个调用链路卡死。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网关。具体操作,请参见添加入口网关服务。本文将ASM网关部署在istio-system命名空间。
    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
  • 使用以下内容创建虚拟服务。具体操作,请参见管理虚拟服务
    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

ASMLocalRateLimiter声明式配置介绍

ASM通过CRD ASMLocalRateLimiter实现本地限流的声明式配置。配置Spec说明如下:

字段 类型 说明 是否必须
workloadSelector map<string, string> 通过一个或多个标签,指明限流配置生效的一组特定的Pod或VM。标签搜索的范围限制在资源所在的配置命名空间。更多信息,请参见Workload Selector Yes
isGateway bool 默认为false No
configs LocalRateLimiterConfig[] 本地限流配置,可配置多条。 Yes

LocalRateLimiterConfig属性字段

字段 类型 说明 是否必须
name string 单条限流配置的名称。 No
match RatelimitMatch 匹配条件。 No
limit LimitConfig 限流阈值配置。 No
RatelimitMatch属性字段
字段 类型 说明 是否必须
vhost VirtualHostMatch VirtualHost匹配条件。 No

LimitConfig属性字段

字段 类型 说明 是否必须
fill_interval Duration 令牌填充时间单位,例如seconds: 1或者nanos: 1000 。nanos表示纳秒。 No
quota int 令牌数量,必须为整数,例如:1000。 No
per_downstream_connection bool 指定速率限制器的令牌桶的范围。默认为false
取值说明如下:
  • false:令牌桶将在所有工作线程中共享,速率限制将应用于每个Envoy进程。
  • true:为每个连接分配一个令牌桶,速率限制适用于每个连接,允许在每个连接的基础上对请求进行速率限制。
说明 仅支持ASM版本≥1.13.4。
No
custom_response_body string 当请求被限制时,自定义返回Body 内容。
说明 仅支持ASM版本≥1.13.4。
No
response_header_to_add map[string]string 当请求被限制时,自定义添加Header内容。
说明 仅支持ASM版本≥1.13.4。
No

VirtualHostMatch属性字段

字段 类型 说明 是否必须
name string 匹配的VirtulHost名称。 No
port int 匹配的请求端口。 No
route RouteMatch 匹配的请求接口对应的路由名称。 No

RouteMatch属性字段

字段 类型 说明 是否必须
name_match string 匹配的路由名称,对应VirtualService下的单条路由名称。 No
header_match HeaderMatcher[] 匹配服务请求的header,支持配置多个。 No

HeaderMatcher属性字段

字段 类型 说明 是否必须
name string header名称。 No
regex_match string 正则表达式匹配。 No
exact_match string 精确匹配。 No
prefix_match string 前缀匹配,以什么开头进行匹配。 No
suffix_match string 后缀匹配,以什么结尾进行匹配。 No
present_match bool 如果配置为true,则不关心该header value的具体取值,只需要header存在即可。 No
invert_match bool 默认为false,如果设置为true,则正则匹配结果取反。 No

适用对象

ASM本地限流功能适用于ASM网关和应用服务(注入了Sidecar)。
说明 场景示例涉及的配置文件,您可以通过此文件下载。

场景示例说明

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

网关限流

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

使用kubectl连接ASM,具体操作,请参见通过kubectl连接ASM实例。然后使用以下内容,创建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
  • 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连接ASM实例
  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连接ASM实例
  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连接ASM实例
  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连接ASM实例。然后使用以下内容,创建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连接ASM实例
  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连接ASM实例
  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服务未受到限流。