在大促等场景下,瞬间洪峰流量会使系统超出最大负载,调用大量堆积,导致整个调用链路卡死。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网关。具体操作,请参见创建入口网关服务
    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声明式配置介绍

说明

ASMLocalRateLimiter CRD的apiVersion字段说明如下:

  • 若ASM实例版本为1.15.3.105及以上,支持使用apiVersion: istio.alibabacloud.com/v1。若您在ACK集群进行了相关配置,请将对应的ASMLocalRateLimiter CRD中的apiVersion: istio.alibabacloud.com/v1beta1修改为apiVersion: istio.alibabacloud.com/v1,再重新进行部署。
  • 若ASM实例版本为1.15.3.105以下,支持使用apiVersion: istio.alibabacloud.com/v1beta1

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

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

LocalRateLimiterConfig属性字段

字段类型说明是否必须
namestring单条限流配置的名称。Yes
matchRatelimitMatch匹配条件。Yes
limitLimitConfig限流阈值配置。Yes
RatelimitMatch属性字段
字段类型说明是否必须
vhostVirtualHostMatchVirtualHost匹配条件。No

LimitConfig属性字段

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

VirtualHostMatch属性字段

字段类型说明是否必须
namestring匹配的VirtualHost名称。Yes
portint匹配的请求端口。No
routeRouteMatch匹配的请求接口对应的路由名称。No

RouteMatch属性字段

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

HeaderMatcher属性字段

字段类型说明是否必须
namestringheader名称。No
regex_matchstring正则表达式匹配。No
exact_matchstring精确匹配。No
prefix_matchstring前缀匹配,以什么开头进行匹配。No
suffix_matchstring后缀匹配,以什么结尾进行匹配。No
present_matchbool如果配置为true,则不关心该header value的具体取值,只需要header存在即可。No
invert_matchbool默认为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服务未受到限流。