istio 速率限制
Envoy 支持两种速率限制:全局和本地。全局速率限制使用全局 gRPC 速率限制服务为整个网格提供速率限制。本地速率限制用于限制每个服务实例的请求速率。
本地速率限制可以与全局速率限制结合使用,以减少全局速率限制服务的负载。例如,本地令牌桶速率限制可以吸收非常大的负载突发,否则可能会压垮全局速率限制服务。因此,速率限制分两个阶段应用。初始粗粒度限制由令牌桶限制执行,然后细粒度全局限制完成作业。
1、全局速率限制
1.1、通过configmap设置限制策略
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、创建全局速率限制服务
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
发现在dynamic_listeners中增加了限速的配置,通过cluster配置找到限速服务。envoy配置:
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" }]
因为没有指定虚拟主机,所以所有的路由都走这个配置。
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、测试所有路由
基于官网配置,不修改别的配置,执行两个接口如下返回。
修改configmap频率限制配置, 访问/productpage也变成了5次200,5次429。
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
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
配置集中于dynamic_listeners的virtualInbound中,端口是15006,15006是 Envoy 代理的入站(Inbound)监听端口。
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