限流是一种限制发送到服务端的请求数量的机制,Envoy使用令牌桶算法实现本地限流。本文介绍如何在ASM中配置本地限流。
前提条件
- 已创建ASM实例,且ASM实例符合以下要求:
- 如果您使用的是ASM商业版(专业版),需要版本≥v1.14.3。关于升级ASM实例的具体操作,请参见升级ASM实例。
- 如果您使用的是ASM标准版,仅支持Istio原生方式配置本地限流功能,且需要版本≥v1.9。不同Istio版本需参考相应版本文档,关于最新的Istio版本配置本地限流功能的具体操作,请参见Enabling Rate Limits using Envoy。
- 已创建Kubernetes托管版集群。具体操作,请参见创建Kubernetes托管版集群。
- 已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
- 已为Kubernetes集群中的default命名空间开启自动注入。具体操作,请参见多种方式灵活开启自动注入。
什么是限流?
限流的概念
限流是一种限制发送到服务端的请求数量的机制。它指定客户端在给定时间段内可以向服务端发送的最大请求数,通常表示为一段时间内的请求数,例如每分钟300个请求或每秒10个请求等。限流的目的是防止服务因来自同一客户端IP或来自任何客户端的全局请求而过载。
以每分钟300个请求的限流机制为例,向服务发送301个请求,限流器将拒绝第301个请求。同时,限流器会返回一个429 HTTP状态码(Too Many Requests),并在请求到达服务之前进行拒绝。
限流的方式
Envoy代理实现限流主要有以下两种方式:
方式 | 说明 |
---|---|
全局(或分布式)限流 |
|
本地限流 |
|
本地限流的工作原理
Envoy使用令牌桶算法实现本地限流。令牌桶算法是一种限制发送到服务端的请求数量的方法,基于一定数量的令牌桶。存储桶以恒定的速率不断填充令牌,当向服务发送请求时,会从存储桶中删除一个令牌。如果存储桶为空,则请求将被拒绝。通常需要指定以下内容:
- 桶被填充的速率(填充间隔)。
- 每个填充间隔添加到桶中的令牌数。
默认情况下,当速率限制器拒绝请求,并设置x-envoy-ratelimited响应标头时,Envoy会发送状态码为429的HTTP响应。您也可以将速率限制器配置为返回自定义HTTP状态代码,并配置其他响应标头。
此外,使用速率限制器有以下两个重要概念:
- 启用速率限制器:表示正在对速率限制器进行配置,但速率限制器并未应用于请求。
- 执行速率限制器:表示对请求应用或执行速率限制器。
将这两个值表示为传入请求的百分比,例如可以设置为10%的请求启用速率限制器,并为5%的请求强制执行。按照这种方式,可以逐步推出限流,并在对所有请求强制执行之前对其进行测试。
配置本地限流
步骤一:部署示例服务
- 使用以下内容,创建httpbin.yaml。
################################################################################################## # httpbin Service示例。 ################################################################################################## apiVersion: v1 kind: ServiceAccount metadata: name: httpbin --- apiVersion: v1 kind: Service metadata: name: httpbin labels: app: httpbin service: httpbin spec: ports: - name: http port: 8000 targetPort: 80 selector: app: httpbin --- apiVersion: apps/v1 kind: Deployment metadata: name: httpbin spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: serviceAccountName: httpbin containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 80
- 执行以下命令,创建httpbin应用。
kubectl apply -f httpbin.yaml -n default
- 使用以下内容,创建sleep.yaml。
################################################################################################## # Sleep Service示例。 ################################################################################################## apiVersion: v1 kind: ServiceAccount metadata: name: sleep --- apiVersion: v1 kind: Service metadata: name: sleep labels: app: sleep service: sleep spec: ports: - port: 80 name: http selector: app: sleep --- apiVersion: apps/v1 kind: Deployment metadata: name: sleep spec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: terminationGracePeriodSeconds: 0 serviceAccountName: sleep containers: - name: sleep image: curlimages/curl command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /etc/sleep/tls name: secret-volume volumes: - name: secret-volume secret: secretName: sleep-secret optional: true ---
- 执行以下命令,创建sleep应用。
kubectl apply -f sleep.yaml -n default
- 进入sleep Pod,执行以下命令,向httpbin服务发送多个请求。
while true; do curl http://httpbin:8000/headers; done
步骤二:定义与执行限流策略
当速率限制器拒绝请求时,您可以使用系统默认的响应信息或自定义响应信息。
- 登录ASM控制台。
- 在左侧导航栏,选择 。
- 在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
- 在网格详情页面左侧导航栏,选择 。
- 在本地限流页面,单击新建,配置命名空间为default,选择任意场景模板,按需选择以下YAML进行配置。
- 默认响应信息:
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMLocalRateLimiter metadata: name: httpbin namespace: default spec: workloadSelector: labels: app: httpbin configs: - match: vhost: name: "*" port: 8000 route: header_match: - name: ":path" prefix_match: "/" limit: fill_interval: seconds: 60 quota: 10
- 自定义响应信息:
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMLocalRateLimiter metadata: name: httpbin namespace: default spec: workloadSelector: labels: app: httpbin configs: - match: vhost: name: "*" port: 8000 route: header_match: - name: ":path" prefix_match: "/" limit: fill_interval: seconds: 60 quota: 10 custom_response_body: '{"custom": "custom message", "message": "Your request be limited" }' response_header_to_add: x-rate-limited: 'TOO_MANY_REQUESTS' x-local-rate-limit: 'enabled'
- 默认响应信息:
- 执行以下命令,发送10个请求。
curl -v httpbin:8000/headers
预期输出:- 默认响应信息:
由预期输出得到,返回x-local-rate-limit响应头和HTTP 429的状态码。* Trying 192.168.250.89:8000... * Connected to httpbin (192.168.250.89) port 8000 (#0) > GET /headers HTTP/1.1 > Host: httpbin:8000 > User-Agent: curl/7.85.0-DEV > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 429 Too Many Requests < x-local-rate-limit: true < content-length: 18 < content-type: text/plain < date: Tue, 27 Sep 2022 07:42:08 GMT < server: envoy < x-envoy-upstream-service-time: 0
- 自定义响应信息:
由预期输出得到,返回自定义的响应头和HTTP状态码。* Trying 192.168.250.89:8000... * Connected to httpbin (192.168.250.89) port 8000 (#0) > GET /headers HTTP/1.1 > Host: httpbin:8000 > User-Agent: curl/7.85.0-DEV > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 429 Too Many Requests < x-local-rate-limit: enabled < x-rate-limited: TOO_MANY_REQUESTS < content-length: 67 < content-type: text/plain < date: Tue, 27 Sep 2022 11:45:45 GMT < server: envoy < x-envoy-upstream-service-time: 0 < * Connection #0 to host httpbin left intact {"custom": "custom message", "message": "Your request be limited" }
- 默认响应信息:
限流相关指标
Envoy中的限流功能会产生以下指标:
以上指标以
Metric | 描述 |
---|---|
<stat_prefix>.http_local_rate_limit.enabled | 触发限流的请求总数。 |
<stat_prefix>.http_local_rate_limit.ok | 来自令牌桶的限流响应总数。 |
<stat_prefix>.http_local_rate_limit.rate_limited | 没有令牌的响应总数(但不一定强制执行)。 |
<stat_prefix>.http_local_rate_limit.enforced | 收到限流响应的总数(例如返回429)。 |
<stat_prefix>.http_local_rate_limit
为前缀,其中<stat_prefix>
是指在stat_prefix
字段中配置的值(例如http_local_rate_limiter
)。在Prometheus中查看限流相关指标
- 执行以下命令,启用Envoy收集统计信息。在Deployment YAML中的
spec.template.metadata
下添加annotations
,来启用Envoy收集统计信息。kubectl patch deployment httpbin --type merge -p '{"spec":{"template":{"metadata":{"annotations":{"proxy.istio.io/config":"proxyStatsMatcher:\n inclusionRegexps:\n - \".*http_local_rate_limit.*\""}}}}}'
- Pod自动重启后,向httpbin服务发送多个请求。
curl -v httpbin:8000/headers
预期输出:envoy_http_local_rate_limiter_http_local_rate_limit_enabled{} 37 envoy_http_local_rate_limiter_http_local_rate_limit_enforced{} 17 envoy_http_local_rate_limiter_http_local_rate_limit_ok{} 20 envoy_http_local_rate_limiter_http_local_rate_limit_rate_limited{} 17
- 通过自建Prometheus监控或ARMS控制台查看限流相关指标。使用ARMS控制台查看限流相关指标的具体操作如下: