a6-plugin-limit-req
概述
limit-req 插件使用漏桶算法对请求进行限流。与采用固定窗口的 limit-count 不同,它通过可配置的延迟限制突发请求,从而实现平滑的流量整形,避免流量峰值压垮上游服务。
适用场景
- 平滑流量,保护上游服务免受突发流量影响。
- 实施每秒 QPS 限制。
- 延迟超额请求,而不是立即拒绝。
- 与
limit-count结合使用,同时实施每秒和每小时限制。
插件配置参考
核心字段
| 字段 | 类型 | 是否必填 | 默认值 | 描述 |
|---|---|---|---|---|
rate | number | 是 | — | 持续的每秒请求数(QPS),必须大于 0 |
burst | number | 是 | — | 超出 rate 的额外突发容量,必须大于等于 0 |
key | string | 是 | — | 用于统计请求的变量 |
key_type | string | 否 | "var" | 键类型:"var" 或 "var_combination" |
rejected_code | integer | 否 | 503 | 拒绝请求时的 HTTP 状态码(200 至 599) |
rejected_msg | string | 否 | — | 自定义拒绝消息正文 |
nodelay | boolean | 否 | false | 设为 true 时,不延迟突发请求 |
allow_degradation | boolean | 否 | false | 插件失败时是否允许请求通过 |
policy | string | 否 | "local" | 存储策略:"local"、"redis" 或 "redis-cluster" |
Redis 字段(policy: "redis" 时)
| 字段 | 类型 | 是否必填 | 默认值 |
|---|---|---|---|
redis_host | string | 是 | — |
redis_port | integer | 否 | 6379 |
redis_username | string | 否 | — |
redis_password | string | 否 | — |
redis_database | integer | 否 | 0 |
redis_timeout | integer | 否 | 1000 |
redis_ssl | boolean | 否 | false |
Redis 集群字段(policy: "redis-cluster" 时)
| 字段 | 类型 | 是否必填 | 默认值 |
|---|---|---|---|
redis_cluster_nodes | 字符串数组 | 是 | — |
redis_cluster_name | string | 是 | — |
redis_password | string | 否 | — |
redis_timeout | integer | 否 | 1000 |
redis_cluster_ssl | boolean | 否 | false |
漏桶算法
Incoming requests → [ Bucket (burst capacity) ] → Leak at 'rate' per second → Upstream
↓ overflow (> rate + burst)
Rejected (503/429)
| 请求速率 | 行为 |
|---|---|
≤ rate | 立即处理 |
> rate 且 ≤ rate + burst | nodelay: false 时延迟处理以平滑流量;nodelay: true 时立即处理 |
> rate + burst | 使用 rejected_code 拒绝 |
nodelay 说明
nodelay: false(默认值):延迟突发请求以平滑流量。突发请求的延迟更高,但可保护上游服务。nodelay: true:不延迟突发请求,立即处理。延迟更低,但上游服务会承受最高rate + burst的流量峰值。
分步操作:基础限流
1. 严格 QPS 限制(无突发容量)
a6 route create -f - <<'EOF'
{
"id": "strict-qps",
"uri": "/api/*",
"plugins": {
"limit-req": {
"rate": 10,
"burst": 0,
"key": "remote_addr",
"rejected_code": 429,
"nodelay": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
每个 IP 每秒允许 10 个请求,超出部分会被立即拒绝。
2. 使用突发容量平滑流量
a6 route create -f - <<'EOF'
{
"id": "smooth-api",
"uri": "/api/*",
"plugins": {
"limit-req": {
"rate": 5,
"burst": 10,
"key": "remote_addr",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
- 持续速率为 5 req/s。
- 最多允许额外 10 个突发请求,并通过延迟平滑流量。
- 超过 15/s 的请求返回 429。
常见模式
多变量键
{
"plugins": {
"limit-req": {
"rate": 10,
"burst": 5,
"key_type": "var_combination",
"key": "$remote_addr $http_x_api_version",
"rejected_code": 429
}
}
}
按 IP 与 API 版本请求头的组合分别使用独立桶。
组合使用 limit-req 和 limit-count
{
"plugins": {
"limit-req": {
"rate": 10,
"burst": 20,
"key": "remote_addr",
"rejected_code": 429
},
"limit-count": {
"count": 1000,
"time_window": 3600,
"key": "remote_addr",
"rejected_code": 429
}
}
}
limit-req:平滑每秒流量(10 QPS,带突发容量)。limit-count:实施每小时配额(1000/小时)。
这样既能防止短期流量峰值,也能防止长期滥用。
使用 Redis 进行分布式限流
{
"plugins": {
"limit-req": {
"rate": 100,
"burst": 50,
"key": "remote_addr",
"policy": "redis",
"redis_host": "redis.example.com",
"redis_port": 6379,
"redis_password": "secret",
"rejected_code": 429
}
}
}
limit-req 与 limit-count 的对比
| 对比维度 | limit-req | limit-count |
|---|---|---|
| 算法 | 漏桶 | 固定窗口 |
| 单位 | 每秒请求数 | 每个时间窗口的请求数 |
| 突发流量处理 | 延迟或允许 | 直接拒绝 |
| 流量整形 | 平滑 | 窗口边界处可能突发 |
| 响应头 | 无 | X-RateLimit-* |
| 组支持 | 否 | 是 |
| 最适用场景 | QPS 保护、流量整形 | 配额实施、API 套餐 |
故障排查
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 突发请求延迟较高 | nodelay: false 会延迟请求 | 设置 nodelay: true 以降低延迟 |
| 所有突发请求都被拒绝 | burst: 0 | 增加 burst 以允许一定的超额请求 |
| 没有返回限流响应头 | limit-req 不会添加响应头 | 如需响应头,请使用 limit-count |
| 限制未在 Apache APISIX节点间共享 | policy: "local" | 切换为 "redis" 或 "redis-cluster" |
| 键为空,所有请求共用一个桶 | 变量不存在 | 检查键变量名称 |
配置同步示例
version: "1"
routes:
- id: smooth-api
uri: /api/*
plugins:
limit-req:
rate: 10
burst: 20
key: remote_addr
rejected_code: 429
upstream_id: api-upstream
upstreams:
- id: api-upstream
type: roundrobin
nodes:
"backend:8080": 1
本文根据 api7/a6 仓库中的 a6-plugin-limit-req/SKILL.md 生成。可在 AI Agent Skills 页面浏览全部 Skill。