Istio本地限流Network Filter运行一段时间后失效问题排查
环境与背景
在K8s集群中运行监听8443端口的HTTPS Go服务,集群边缘部署了监听443端口的Istio入口网关。通过配置Virtual Service(匹配/testgo转发至服务443端口)、Destination Rule(使用SIMPLE TLS)实现了外部https://GATEWAY_HOST/testgo的访问。
注入Istio Sidecar后,为保持后端HTTPS访问将peerAuthentication设为DISABLE,导致官方文档的HTTP本地限流过滤器失效。改用NETWORK_FILTER类型的本地限流后,初始运行正常,但一段时间后出现限流失效的情况,当前使用Istio 1.15版本。
当前EnvoyFilter配置
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: go-server-ratelimit namespace: default spec: workloadSelector: labels: app: web configPatches: - applyTo: NETWORK_FILTER match: context: SIDECAR_INBOUND listener: portNumber: 8443 filterChain: filter: name: "envoy.filters.network.tcp_proxy" patch: operation: INSERT_BEFORE value: name: envoy.filters.local_ratelimit typed_config: "@type": type.googleapis.com/udpa.type.v1.TypedStruct type_url: type.googleapis.com/envoy.extensions.filters.network.local_ratelimit.v3.LocalRateLimit value: stat_prefix: local_rate_limiter token_bucket: max_tokens: 1 tokens_per_fill: 1 fill_interval: 60s runtime_enabled: default_value: true runtime_key: go-server-ratelimit share_key: go-server-ratelimit
测试脚本
cnt=1 delay=60 while true do http_code=`curl -k -o /dev/null -s -w "%{http_code}" "https://GATEWAY_HOST/testgo/"` if [ $http_code -ne 200 ] then echo "HTTP return code is $http_code after $((cnt-1)) tries, sleeping for $delay seconds" sleep $delay cnt=1 else echo "HTTP return code is $http_code on try $cnt" cnt=$((cnt+1)) fi done
异常现象
预期为每分钟仅允许1个HTTP请求成功,但运行一段时间后,过滤器允许多个请求通过,测试输出片段如下:
HTTP return code is 200 on try 1 HTTP return code is 503 after 1 tries, sleeping for 60 seconds ... HTTP return code is 200 on try 1 HTTP return code is 200 on try 2 HTTP return code is 200 on try 3 HTTP return code is 200 on try 4 ... HTTP return code is 503 after 10 tries, sleeping for 60 seconds
问题根源与解决方案
问题根源
你使用的envoy.filters.network.local_ratelimit是TCP层限流过滤器,它只能针对TCP连接进行限流,无法识别上层的HTTP请求。当客户端开启连接复用(如curl默认启用keep-alive)时,多个HTTP请求会通过同一个TCP连接发送,该过滤器仅在连接建立时消耗1个令牌,后续同一连接内的所有HTTP请求都不会触发限流检查,因此出现“限流失效”的现象——实际是多个请求复用了已通过限流的TCP连接。
正确配置方案
要实现HTTP请求级别的精准限流,必须切换到HTTP_FILTER类型的限流过滤器,同时调整PeerAuthentication配置以支持流量解密:
调整PeerAuthentication配置
不要直接设置为DISABLE,改用PERMISSIVE模式允许TLS与非TLS流量,或针对特定服务设为STRICT,确保Sidecar能解密后端HTTPS流量以解析HTTP请求:apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: default spec: mtls: mode: PERMISSIVE使用HTTP_FILTER类型的本地限流EnvoyFilter
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: go-server-ratelimit namespace: default spec: workloadSelector: labels: app: web configPatches: - applyTo: HTTP_FILTER match: context: SIDECAR_INBOUND listener: portNumber: 8443 filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" 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: local_rate_limiter token_bucket: max_tokens: 1 tokens_per_fill: 1 fill_interval: 60s runtime_enabled: default_value: true runtime_key: go-server-ratelimit 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"确保Destination Rule配置正确
保持Sidecar与后端服务的TLS通信配置,确保流量解密正常:apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: web-service namespace: default spec: host: web.default.svc.cluster.local trafficPolicy: tls: mode: SIMPLE
临时Workaround(若必须使用NETWORK_FILTER)
如果暂时无法切换到HTTP_FILTER,可在测试脚本中强制关闭连接复用,确保每次请求建立新TCP连接:
http_code=`curl -k -H "Connection: close" -o /dev/null -s -w "%{http_code}" "https://GATEWAY_HOST/testgo/"`
该方案会带来性能损耗,仅作为临时验证使用。
内容的提问来源于stack exchange,提问作者Dattaram Porob

