3. Kong 内置 Rate Limiting 插件详解:插件工作原理、配置参数
Rate Limiting(速率限制)是 API 网关最核心的流量控制手段之一。Kong 内置的 Rate Limiting 插件基于滑动窗口算法实现,能够在分布式或单节点环境下精确限制客户端在指定时间窗口内的请求次数,防止后端服务被突发流量冲垮。
3.1 插件工作原理
Rate Limiting 插件的核心逻辑可概括为:在每个时间窗口内,为每个消费者(或 IP、凭证等)维护一个计数器,当请求到达时递增计数器,若计数器超过阈值则拒绝请求。其工作流程如下:
- 请求到达:客户端请求进入 Kong,插件根据
config.limit_by确定计数对象(消费者、IP、凭证等)。 - 计数器查询:从后端存储(本地内存、Redis 或集群共享存储)读取当前时间窗口的计数器值。
- 阈值判断:若当前计数器值 < 配置的速率上限,则允许请求通过,并将计数器 +1;否则返回
429 Too Many Requests。 - 窗口滑动:时间窗口按秒、分、时、天、月、年自然滑动,旧窗口数据自动过期。
关键特性:Kong 的 Rate Limiting 插件支持多时间窗口同时生效。例如,同时配置
config.second=5 和 config.minute=200,则每秒最多 5 次,每分钟最多 200 次,两个限制独立计数,任一达到阈值即触发限流。
3.2 配置参数详解
Rate Limiting 插件的配置参数分为时间窗口参数、计数维度参数和存储策略参数三大类。以下逐一说明:
3.2.1 时间窗口参数
插件支持 6 个独立的时间窗口,每个窗口可单独设置请求上限。这些参数可以任意组合使用,系统会同时检查所有已配置的窗口:
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
config.second |
number | null | 每秒允许的最大请求数 |
config.minute |
number | null | 每分钟允许的最大请求数 |
config.hour |
number | null | 每小时允许的最大请求数 |
config.day |
number | null | 每天允许的最大请求数 |
config.month |
number | null | 每月允许的最大请求数 |
config.year |
number | null | 每年允许的最大请求数 |
实践建议:生产环境中推荐至少配置
config.second 和 config.minute 两个窗口。秒级窗口用于防止突发流量,分钟级窗口用于控制平均速率。例如:config.second=10 + config.minute=300。
3.2.2 计数维度参数:config.limit_by
config.limit_by 决定以什么维度对请求进行分组计数,即“限制谁”。可选值及含义如下:
| 取值 | 计数对象 | 适用场景 |
|---|---|---|
consumer |
Kong Consumer 实体 | 按用户/应用维度限流,需配合认证插件使用 |
credential |
认证凭证(如 ) | 按凭证粒度限流,一个消费者多个凭证时独立计数 |
ip |
客户端 IP 地址 | 按来源 IP 限流,防止单个 IP 滥用 |
service |
Kong Service 实体 | 按服务维度限流,所有请求共享一个计数器 |
header |
自定义请求头值 | 按特定 Header 值限流,需配合 config.header_name 使用 |
path |
请求路径 | 按 URI 路径限流,不同路径独立计数 |
注意:当
config.limit_by 设置为 consumer 时,如果请求未通过认证(即没有关联 Consumer),插件会使用 config.fault_tolerant 决定是否放行。建议在开启 Consumer 限流前确保认证插件已正确配置。
3.2.3 存储策略参数:config.policy
config.policy 决定计数器数据的存储方式,直接影响限流的准确性和性能:
| 取值 | 存储后端 | 特点 | 推荐场景 |
|---|---|---|---|
local |
节点内存 | 性能最高,无网络开销;但各节点计数器独立,不共享 | 单节点部署或允许近似限流 |
redis |
Redis 服务器 | 集群共享计数器,精确限流;有网络延迟 | 多节点集群,需要精确全局限流 |
cluster |
Kong 集群共享存储(已弃用) | 旧版集群模式,性能较差 | 不推荐新项目使用 |
3.3 配置示例
以下是一个完整的 Rate Limiting 插件配置示例,通过 Admin API 创建:
curl -X POST http://localhost:8001/routes/{route_id}/plugins \
--header "Content-Type: application/json" \
--data '{
"name": "rate-limiting",
"config": {
"second": 5,
"minute": 200,
"hour": 5000,
"limit_by": "consumer",
"policy": "redis",
"redis_host": "192.168.1.100",
"redis_port": 6379,
"redis_password": "securepass",
"redis_database": 0,
"redis_timeout": 2000,
"fault_tolerant": true,
"hide_client_headers": false
}
}'
参数说明:
redis_host/redis_port:Redis 服务器地址和端口,仅在policy=redis时生效。redis_password:Redis 认证密码,可选。redis_database:Redis 数据库编号,默认 0。redis_timeout:Redis 连接超时时间(毫秒),默认 2000。fault_tolerant:当 Redis 不可用时是否放行请求。设为true可避免 Redis 故障导致全局限流失效。hide_client_headers:是否在响应头中隐藏限流信息(X-RateLimit-Limit、X-RateLimit-Remaining等)。
3.4 常见故障排查
| 故障现象 | 可能原因 | 排查方法 |
|---|---|---|
| 限流不生效,请求全部通过 | 插件未正确绑定到 Route/Service;config.policy 配置错误 |
检查插件列表确认已启用;检查 Redis 连接是否正常 |
| 限流过于严格,正常请求被误杀 | 多时间窗口叠加效应;config.limit_by 粒度过细 |
检查所有配置窗口的阈值;确认计数维度是否符合预期 |
| 集群中各节点限流不一致 | 使用了 local 策略而非 redis 策略 |
切换为 redis 策略并确保所有节点指向同一 Redis 实例 |
| Redis 故障后所有请求被拒绝 | config.fault_tolerant 设为 false |
将 fault_tolerant 设为 true,允许 Redis 不可用时降级 |
最佳实践:在正式上线前,建议使用
config.second=99999 等极大值进行灰度验证,确认插件绑定和计数逻辑正确后,再逐步收紧阈值。同时开启 hide_client_headers=false 以便在响应头中观察剩余配额。