Nginx限流应分层分级:按IP+接口、域名、用户标识设不同limit_req_zone;burst与nodelay需依业务选配;须记录$limit和$limit_key日志,改状态码为429,并配足共享内存;还需叠加limit_conn防连接耗尽。

直接在 Nginx 负载均衡层用 limit_req 模块做限流,是最高效、侵入性最小的突发流量防护手段。它不依赖后端代码,也不增加业务延迟,关键在于把“控速”和“缓冲”逻辑前置到流量入口。
按业务路径分级定义限流区域
不能只用一个全局规则。要结合 limit_req_zone 的 key 设计,区分不同风险等级的流量:
-
按 IP + 接口粒度:保护高危路径,例如登录、下单、支付回调
用$binary_remote_addr$uri作 key,避免单个恶意 IP 刷爆整个服务 -
按域名隔离:防止某个子站突发拖垮其他业务
用$host作 key,让api.example.com和admin.example.com互不影响 -
按用户标识(需 header 透传):对已登录用户做更精细控制
例如用$http_x_user_id,配合后端鉴权,避免未登录时 fallback 到 IP 粗粒度限制
burst 和 nodelay 的组合要匹配业务容忍度
burst 不是越大越好,nodelay 更不是默认开关。它们的作用完全不同:
-
普通查询类接口(如列表页、详情页):
设burst=10,不加nodelay—— 允许排队,平滑释放压力,避免前端密集重试 -
关键事务类接口(如 /api/order/create):
设burst=3+nodelay—— 前几笔请求立刻响应,后续严格按速率放行;前提是后端已压测验证能扛住这 3 笔并发 -
防御型接口(如短信发送、密码重置):
设burst=1+nodelay或干脆不设 burst —— 几乎不允许突发,防轰炸
必须搭配日志与监控闭环
限流生效后如果没日志,等于盲操作。出问题时根本不知道是哪个 IP 或哪个 key 触发了拒绝:
- 在
log_format中加入$limit(触发的 zone 名)和$limit_key(实际统计的 key 值) - 用
limit_req_status 429把拒绝状态码从默认 503 改为标准限流码,方便前端识别并退避 - 定期检查共享内存 zone 使用率:
nginx -T 2>/dev/null | grep "zone=.*:" | awk '{print $3}'对应的 size 是否足够
1MB ≈ 存 1.6 万个 key,若日活 IP 50 万,zone 至少配 32MB,否则旧记录被挤掉,限流失效
别只靠 limit_req,补上连接层防护
漏桶算法管的是“请求速率”,但攻击者可能建大量慢连接耗尽 socket。必须叠加 limit_conn:
- 用
limit_conn_zone $binary_remote_addr zone=conn_perip:10m定义连接数限制区 - 在 location 中加
limit_conn conn_perip 100,防慢速 HTTP 攻击或连接泄漏 - 两者共存时,Nginx 先检查连接数,再检查请求速率,任一超限即拒

















