limit_req 配合 burst 的核心是为突发请求提供缓冲队列,使其排队匀速放行而非瞬间击穿后端或直接返回503;需先在http块定义limit_req_zone(推荐$binary_remote_addr作key),再于location中用limit_req zone=name burst=n [nodelay]启用,burst值应据业务qps合理设定并配合日志监控调优。

直接用 limit_req 配合 burst,核心是给突发请求一个“缓冲队列”,让它排队等节奏放行,而不是瞬间打垮后端或直接返回 503。关键不在压低速率,而在控制排队行为和容量。
先定义合理的限流区域(zone)
在 http 块里声明共享内存区,推荐用 $binary_remote_addr 作 key,省空间、查得快:
-
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;—— 每秒最多处理 10 个请求,10MB 内存够存约 16 万个 IP 状态 - 若需按用户 ID 限流(比如防薅羊毛),改用
$arg_user_id或$http_x_user_id,确保前端透传 - 代理环境下(如 CDN 或 LB),
$binary_remote_addr会失效,应改用可信的$http_x_forwarded_for并配合set_real_ip_from
在具体 location 中启用 burst 缓冲
只对需要保护的接口生效,比如 /api/order 或 /login:
-
limit_req zone=api burst=30;—— 允许最多 30 个请求暂存排队,超出即拒(默认行为) -
limit_req zone=api burst=30 nodelay;—— 超出 rate 但未超 burst 的请求立刻通过,不排队(适合下单、登录等强实时场景) -
limit_req zone=api burst=30 delay=15;—— 前 15 个超限请求被匀速延迟放行(响应头带X-RateLimit-Delay),后 15 个直接拒
burst 值怎么设才靠谱
不能凭感觉填,要结合业务实际:
- 读接口(如商品详情):日常 QPS 是 50,burst 可设为 100~150,相当于容纳 2 秒左右突发
- 写接口(如下单):慎用纯排队,优先选
burst + nodelay,但必须确认后端能扛住这波并发(比如压测过 30 笔同时下单) - 健康检查或静态资源:burst=0 更合适,避免干扰监控或缓存命中
- burst 过大(如 1000)+ nodelay = 实际上没限流,只是把失败延后到内存耗尽
让限流行为可观察、可调优
配完不看日志等于没配:
- 加日志变量:
log_format main '... $limit $limit_key $limit_rate';,能看清哪个 key 触发了限流 - 调高日志级别:
limit_req_log_level warn;,记录所有排队/拒绝动作,不只是 error - 监控指标:关注
nginx_http_limit_req_rejected_total和nginx_http_limit_req_delayed_total,上升明显说明 burst 偏小或 rate 偏低 - 压测验证:用 wrk 或 hey 发 50 并发请求,观察响应时间分布是否呈固定间隔(如 100ms、200ms…),确认漏桶节奏生效











