配置限流
限流允许你限制客户端在特定时间窗口内可以向 API 发起的请求数量。它可以防止后端服务因请求过多而被压垮,并确保所有用户公平使用服务。
API7 企业版提供两个用于限流的插件:
limit-count:简单限流插件,用于统计固定时间窗口内的请求 数。limit-count-advanced:高级版本,支持滑动窗口、多规则和 Redis Sentinel。
以下场景复用同一个服务和路由。应用下一个场景前,请先验证当前场景,因为后续场景会更新路由的插件配置,并成为唯一生效的限流器。
前置条件
- API7 企业版实例正在运行。
- 已创建网关组,并且网关实例正在运行。
- 从控制台获取 Token。
配置基础限流
limit-count 插件适合简单限流场景,例如限制每个 IP 地址每分钟最多 5 个请求。
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-service",
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": [
{
"host": "httpbin.org",
"port": 80,
"weight": 100
}
]
}
}'
curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-route",
"methods": ["GET"],
"paths": ["/get"],
"service_id": "rate-limit-service",
"plugins": {
"limit-count": {
"count": 5,
"time_window": 60,
"rejected_code": 429,
"rejected_msg": "Too Many Requests",
"key": "remote_addr",
"policy": "local"
}
}
}'
services:
- name: rate-limit-service
upstream:
nodes:
- host: httpbin.org
port: 80
weight: 1
routes:
- name: rate-limit-route
uris:
- /get
methods:
- GET
plugins:
limit-count:
count: 5
time_window: 60
rejected_code: 429
rejected_msg: "Too Many Requests"
key_type: var
key: remote_addr
policy: local
labels:
docs-example: rate-limit-service
预览本示例管理的资源变更,确认没有非预期的更新或删除:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
审查变更后同步配置:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
发送六次 GET 请求。前五次应成功,第六次应返回 429:
for i in {1..6}; do
curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get"
done
配置分布式限流
在多节点网关部署中,使用 redis 策略可以在所有节点之间共享限流计数器。
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-service",
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": [
{
"host": "httpbin.org",
"port": 80,
"weight": 100
}
]
}
}'
curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-route",
"methods": ["GET"],
"paths": ["/get"],
"service_id": "rate-limit-service",
"plugins": {
"limit-count": {
"count": 5,
"time_window": 60,
"rejected_code": 429,
"policy": "redis",
"redis_host": "127.0.0.1",
"redis_port": 6379,
"redis_password": "your-password",
"redis_database": 0,
"allow_degradation": true
}
}
}'
services:
- name: rate-limit-service
upstream:
nodes:
- host: httpbin.org
port: 80
weight: 1
routes:
- name: rate-limit-route
uris:
- /get
methods:
- GET
plugins:
limit-count:
count: 5
time_window: 60
rejected_code: 429
policy: redis
redis_host: "127.0.0.1"
redis_port: 6379
redis_password: "your-password"
redis_database: 0
allow_degradation: true
labels:
docs-example: rate-limit-service
预览本示例管理的资源变更,确认没有非预期的更新或删除:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
审查变更 后同步配置:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
将 allow_degradation 设置为 true 后,即使 Redis 服务器不可达,也会允许流量通过。
确认 Redis 可达后,发送六次 GET 请求。前五次应成功,第六次应返回 429:
for i in {1..6}; do
curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get"
done
配置高级限流
limit-count-advanced 插件支持滑动窗口算法,可以避免固定窗口边界处可能出现的流量突增。它还允许在单个插件实例中定义多条规则。
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/services/rate-limit-service?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-service",
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": [
{
"host": "httpbin.org",
"port": 80,
"weight": 100
}
]
}
}'
curl -k "https://localhost:7443/apisix/admin/routes/rate-limit-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "rate-limit-route",
"methods": ["GET"],
"paths": ["/get"],
"service_id": "rate-limit-service",
"plugins": {
"limit-count-advanced": {
"window_type": "sliding",
"policy": "local",
"rejected_code": 429,
"rules": [
{
"count": 3,
"time_window": 60,
"key": "$remote_addr"
},
{
"count": 1000,
"time_window": 3600,
"key": "$http_x_api_key"
}
]
}
}
}'
services:
- name: rate-limit-service
upstream:
nodes:
- host: httpbin.org
port: 80
weight: 1
routes:
- name: rate-limit-route
uris:
- /get
methods:
- GET
plugins:
limit-count-advanced:
window_type: sliding
policy: local
rejected_code: 429
rules:
- count: 3
time_window: 60
key: "$remote_addr"
- count: 1000
time_window: 3600
key: "$http_x_api_key"
labels:
docs-example: rate-limit-service
预览本示例管理的资源变更,确认没有非预期的更新或删除:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
审查变更后同步配置:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=rate-limit-service
在此示例中,每个客户端 IP 每分钟最多 3 个请求,每个 API Key 每小时最多 1,000 个请求。
发送四次 GET 请求。前三次应成功,第四次应返回 429:
for i in {1..4}; do
curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1:9080/get" \
-H "X-API-Key: demo-client"
done
解读限流响应
被拒绝的请求会收到配置的 429 Too Many Requests 响应。
如果应用配置后路由立即返回 404,请等待几秒钟,让最新配置下发到网关后再重试。
对于基础和分布式限流场景,如果启用了 show_limit_quota_header(默认为 true),响应还会包含 X-RateLimit 相关响应头:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 45
同时命中两条规则的高级限流请求可能包含每条规则各一组的配额响应头。如果未配置 header_prefix,响应头使用规则索引,例如第一条规则使用 X-1-RateLimit-Limit,第二条规则使用 X-2-RateLimit-Limit。如果第一条规则拒绝请求,后续规则不再评估,因此拒绝响应可能只包含第一条规则的响应头。
故障排查
- Redis 连接问题:确保网关节点能够通过网络访问 Redis 服务器,并且凭证正确。检查网关日志中是否存在连接错误。
limit-count的key_type错误:如果key是remote_addr等请求变量名,将key_type设为var;如果key是字面常量,将其设为constant。limit-count-advanced的规则key无效:规则没有key_type。它的key是变量表达式,因此变量需要$前缀,例如$remote_addr。没有变量引用的值会被跳过;如果所有规则都被跳过,网关默认返回 HTTP500。- Redis 延迟:如果 Redis 延迟影响请求性能,可考虑对高频低延迟限制使用
local策略,或调优基于 Redis 策略的sync_interval。