跳转至

istio 速率限制

  Envoy 支持两种速率限制:全局和本地。全局速率限制使用全局 gRPC 速率限制服务为整个网格提供速率限制。本地速率限制用于限制每个服务实例的请求速率。

本地速率限制可以与全局速率限制结合使用,以减少全局速率限制服务的负载。例如,本地令牌桶速率限制可以吸收非常大的负载突发,否则可能会压垮全局速率限制服务。因此,速率限制分两个阶段应用。初始粗粒度限制由令牌桶限制执行,然后细粒度全局限制完成作业。

1、全局速率限制

1.1、通过configmap设置限制策略

ratelimit

kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: ratelimit-config
data:
  config.yaml: |
    domain: ratelimit
    descriptors:
      - key: PATH
        value: "/productpage"
        rate_limit:
          unit: minute
          requests_per_unit: 1
      - key: PATH
        value: "api"
        rate_limit:
          unit: minute
          requests_per_unit: 2
      - key: PATH
        rate_limit:
          unit: minute
          requests_per_unit: 100
EOF

1.2、创建全局速率限制服务

kubectl apply -f samples/ratelimit/rate-limit-service.yaml

1.3、将全局限速配置插入 ingressGateway的envoy中

这个部分最好提前去学习一下envoy的配置,最起码能看懂。

通过EnvoyFilter创建的资源,在ingress-gateway的envoy配置中插入全局速率限制配置,指定全局速率限制的服务端(类似于我做反爬时的服务端)。

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-ratelimit
  namespace: istio-system
spec:
  workloadSelector:
    # select by label in the same namespace
    labels:
      istio: ingressgateway
  configPatches:
    # The Envoy config you want to modify
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        # Adds the Envoy Rate Limit Filter in HTTP filter chain.
        value:
          name: envoy.filters.http.ratelimit
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
            # domain can be anything! Match it to the ratelimter service config
            domain: ratelimit
            failure_mode_deny: true
            timeout: 10s
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: outbound|8081||ratelimit.default.svc.cluster.local
                  authority: ratelimit.default.svc.cluster.local
              transport_api_version: V3
EOF

1.3.1、查看ingress-gateway的envoy配置

kubectl port-forward --address 0.0.0.0 pod/istio-ingressgateway-64f9774bdc-8qlnj 15000 -n istio-system
通过访问http://127.0.0.1:15000/config_dump

发现在dynamic_listeners中增加了限速的配置,通过cluster配置找到限速服务。envoy配置: 3.1

1.4、定义要限制速率的路由配置

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-ratelimit-svc
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ""
            route:
              action: ANY
      patch:
        operation: MERGE
        # Applies the rate limit rules.
        value:
          rate_limits:
            - actions: # any actions in here
              - request_headers:
                  header_name: ":path"
                  descriptor_key: "PATH"
EOF

当一个请求来临时,http速率限制过滤器将调用速率限制服务,将生成的描述符发送到服务端,类似于Descriptor: [{ "key": "PATH", "value": "/api/v1/products" }]

envoy配置: 4

因为没有指定虚拟主机,所以所有的路由都走这个配置。

1.4.1、rate_limits

1.4.1.1、架构概述

  虽然分布式断路通常对于控制分布式系统中的吞吐量非常有效,但有时它并不是非常有效,需要全局速率限制。最常见的情况是当大量主机转发到少量主机并且平均请求延迟较低(例如,到数据库服务器的连接/请求)时。如果目标主机备份,下游主机将压倒上游集群。在这种情况下,很难在每个下游主机上配置足够严格的断路限制,以使系统在典型请求模式下正常运行,但在系统开始出现故障时仍能防止级联故障。全局速率限制是这种情况的一个很好的解决方案。

Envoy 提供了两种全局速率限制实现:

  • 每个连接或每个 HTTP 请求速率限制检查。

  • 基于配额(目前尚无速率限制服务的开源参考实现。),定期报告负载,允许在 Envoy 的多个实例之间公平共享全局速率限制。此实现适用于每秒请求负载较高的大型 Envoy 部署,这些负载可能无法在所有 Envoy 实例之间均衡。

1.4.1.2、config.route.v3.RateLimit.Action

  要应用于此速率限制配置的操作列表。顺序很重要,因为操作是按顺序处理的,并且描述符是通过按该顺序附加描述符条目来编写的。如果操作无法附加描述符条目,则不会为配置生成描述符。

1.4.1.3、RequestHeaders

Rate limit on request headers,config.route.v3.RateLimit.Action.RequestHeaders,The following descriptor entry is appended when a header contains a key that matches the header_name.

结合上面的配置,就是将uri加入到描述符向量中。 ("<descriptor_key>", "<header_value_queried_from_header>")

1.5、测试所有路由

基于官网配置,不修改别的配置,执行两个接口如下返回。

5

修改configmap频率限制配置, 访问/productpage也变成了5次200,5次429。

- key: PATH
value: "/productpage"
rate_limit:
    unit: minute
    requests_per_unit: 5

1.6、高级用法

1.6.1、修改vs

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: bookinfo
spec:
  gateways:
  - bookinfo-gateway
  hosts:
  - '*'
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    route:
    - destination:
        host: productpage
        port:
          number: 9080
  - match:
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080
    name: api
EOF

1.6.2、细粒度限制

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-ratelimit-svc-api
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
    - applyTo: HTTP_ROUTE
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: "*:8080"
            route:
              name: "api"
      patch:
        operation: MERGE
        value:
          route:
            rate_limits:
            - actions:
              - header_value_match:
                  descriptor_key: "PATH"
                  descriptor_value: "api"
                  headers:
                    - name: ":path"
                      safe_regex_match:
                        google_re2: {}
                        regex: "/api/v1/products/[1-9]{1,2}"
EOF
在envoy的配置中,为某个主机的某个路由增加限制。envoy官网文档中safe_regex_match已经弃用,换成string_match。当有请求进入时,请求的 :path 头将被检查,只有当请求的路径符合正则时,描述符 "PATH" 的值将设置为 "api"。

1.6.3、测试

jichengwei@localhost istio-1.23.2 % for i in `seq 1 10`; do curl -s "http://127.0.0.1/api/v1/products/${i}" -o /dev/null -w "%{http_code}\n"; sleep 3; done

200
200
429
429
429
429
429
429
429
200
根据最初的配置,每分钟两次请求。

2、本地速率限制

2.1、应用于INBOUND所有虚拟主机/路由

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-local-ratelimit-svc
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: productpage
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.local_ratelimit
          typed_config:
            "@type": type.googleapis.com/udpa.type.v1.TypedStruct
            type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
            value:
              stat_prefix: http_local_rate_limiter
              token_bucket:
                max_tokens: 4
                tokens_per_fill: 4
                fill_interval: 60s
              filter_enabled:
                runtime_key: local_rate_limit_enabled
                default_value:
                  numerator: 100
                  denominator: HUNDRED
              filter_enforced:
                runtime_key: local_rate_limit_enforced
                default_value:
                  numerator: 100
                  denominator: HUNDRED
              response_headers_to_add:
                - append: false
                  header:
                    key: x-local-rate-limit
                    value: 'true'
EOF
本地速率限制过滤器的 令牌桶 配置为允许每分钟 4 个请求。该过滤器还配置为x-local-rate-limit 向被阻止的请求添加响应标头。

配置集中于dynamic_listeners的virtualInbound中,端口是15006,15006是 Envoy 代理的入站(Inbound)监听端口。 2.1

2.2、应用于INBOUND 9080端口

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: filter-local-ratelimit-svc
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: productpage
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.local_ratelimit
          typed_config:
            "@type": type.googleapis.com/udpa.type.v1.TypedStruct
            type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
            value:
              stat_prefix: http_local_rate_limiter
    - applyTo: HTTP_ROUTE
      match:
        context: SIDECAR_INBOUND
        routeConfiguration:
          vhost:
            name: "inbound|http|9080"
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          typed_per_filter_config:
            envoy.filters.http.local_ratelimit:
              "@type": type.googleapis.com/udpa.type.v1.TypedStruct
              type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
              value:
                stat_prefix: http_local_rate_limiter
                token_bucket:
                  max_tokens: 4
                  tokens_per_fill: 4
                  fill_interval: 60s
                filter_enabled:
                  runtime_key: local_rate_limit_enabled
                  default_value:
                    numerator: 100
                    denominator: HUNDRED
                filter_enforced:
                  runtime_key: local_rate_limit_enforced
                  default_value:
                    numerator: 100
                    denominator: HUNDRED
                response_headers_to_add:
                  - append: false
                    header:
                      key: x-local-rate-limit
                      value: 'true'
EOF

本文阅读量  次

评论