Nginx 如何实现限流?
简化版
Nginx 主要用两个模块限流:① limit_req(请求速率限流)——基于漏桶算法,限制每秒请求数(QPS),超出速率的请求被延迟处理或拒绝,可用 burst 允许一定突发;② limit_conn(并发连接数限流)——限制同一个 key(如同一 IP)的并发连接数。两者都通过先定义一个共享内存 zone 记录状态,再在 location 里应用。核心是保护后端不被突发流量或恶意请求打垮。
详细版
① 请求速率限流 limit_req(漏桶):
http {
# 定义限流规则:按客户端 IP,速率 10 请求/秒,共享内存 10MB
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
server {
location /api/ {
# 应用限流;burst=20 允许突发 20 个排队,nodelay 不延迟立即处理突发
limit_req zone=req_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
}
② 并发连接限流 limit_conn:
http {
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /download/ {
limit_conn conn_limit 3; # 每个 IP 最多 3 个并发连接
}
}
}
- rate=10r/s:每秒放行 10 个请求(漏桶匀速漏水)。
- burst=20:允许 20 个请求的突发缓冲(桶容量),超出直接拒绝(返回 503)。
- nodelay:突发的请求立即处理而非排队延迟(配合 burst 更实用)。
- limit_conn:限制并发连接数,适合下载、长连接场景。
完整版教学
一、为什么要在 Nginx 层限流
Nginx 是流量入口,在这里限流能把过量请求挡在最外层,保护后端应用和数据库不被突发流量、恶意刷接口、爬虫打垮。相比在应用层限流,Nginx 层限流更靠前、更省资源(超量请求直接被 Nginx 拒绝,根本不占用后端资源)。Nginx 主要提供两种维度的限流:请求速率(QPS) 和 并发连接数。
二、limit_req:基于漏桶的请求速率限流
limit_req 限制的是请求的速率(每秒多少个请求),底层是漏桶算法:
漏桶算法:想象一个底部有孔的桶,请求像水一样倒进桶里,桶底以恒定速率漏水(放行请求)。
rate=10r/s:漏水速率——每秒匀速放行 10 个请求(每 100ms 一个)。- 请求来得比漏水快时,多的先在桶里排队;桶满了(超过容量)就溢出——请求被拒绝(返回 503)。
配置分两步:
limit_req_zone定义规则:按什么 key 限流($binary_remote_addr是客户端 IP)、共享内存区大小、速率。limit_req在 location 里应用这个规则。
三、burst 和 nodelay:处理突发流量
纯漏桶(rate=10r/s)非常严格——超过每秒 10 个就拒绝,但实际流量常有短暂突发(比如某一刻来了 15 个请求,其实系统扛得住)。直接拒绝体验差。用 burst 和 nodelay 优化:
burst=20:允许一个容量为 20 的缓冲队列(桶的容量)。超过rate速率的请求,只要不超过 burst 数量,就先排队等待(按 rate 速率慢慢放行),而不是立即拒绝。只有连 burst 队列都满了才拒绝。这样能吸收突发。nodelay:如果只配 burst 不配 nodelay,突发请求会被延迟处理(按 rate 慢慢放,用户等待久)。加上nodelay,突发的请求立即处理(不排队等待),但仍占用 burst 名额——名额在后续时间里按 rate 慢慢释放。burst + nodelay是实践中最常用的组合,既限了平均速率,又能立即响应突发。
四、limit_conn:并发连接数限流
limit_conn 限制的是同时保持的连接数,而非速率。适合长连接、下载、上传这类场景——比如限制每个 IP 同时只能有 3 个下载连接,防止单个用户开几十个连接占满带宽。
配置同样两步:limit_conn_zone 定义规则(按 IP),limit_conn conn_limit 3 应用(每个 IP 最多 3 个并发连接)。超过的连接被拒绝。
limit_req vs limit_conn:
limit_req管速率(每秒多少请求)——防高频刷接口。limit_conn管并发数(同时多少连接)——防单用户占用过多连接资源。 两者常配合使用。
五、限流的 key 与粒度
限流的维度(key) 决定了「按什么来限」,通过 zone 定义时的变量控制:
$binary_remote_addr:按客户端 IP 限流(最常用,binary形式比$remote_addr省内存)。$server_name:按域名限流。- 自定义变量:如按 URL 参数、请求头里的用户 ID 等限流(更细粒度)。
选对 key 很重要:按 IP 限流对付单机刷接口有效,但如果攻击来自大量不同 IP(分布式),或大量用户在同一 NAT 出口 IP 下,按 IP 就不合适,要结合业务维度。
六、常见误区与追问
| 考点 | 正确口径 |
|---|---|
| 限流目标 | 保护后端、防刷、防突发流量打垮系统 |
| Nginx 手段 | limit_req 限请求速率,limit_conn 限连接数 |
| 算法理解 | 漏桶平滑流量,burst 允许短时排队 |
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
Nginx 限流要说清维度:按 IP、用户、接口还是全局;维度错了就会误伤或漏防。
- 误区:限流只要按 IP 就够。 NAT、代理和真实用户共享 IP 会误伤,登录态场景可按用户或 token 限流。
- 误区:burst 表示无限放行突发流量。 burst 是可排队或瞬时处理的额外请求上限,超过仍会被拒绝。
- 误区:Nginx 限流能替代业务风控。 Nginx 适合入口流量控制,复杂风控仍要结合用户、设备和业务行为。
- 追问:limit_req 和 limit_conn 区别? limit_req 控制请求速率,limit_conn 控制并发连接数。
- 追问:nodelay 有什么影响? 启用后 burst 内请求不排队等待,直接放行但仍受 burst 上限约束。
- 追问:限流后返回什么? 通常返回 503 或自定义状态码,也可配置错误页和降级响应。
七、加强记忆
Nginx 限流两大模块:① limit_req(请求速率)——基于漏桶算法,rate=10r/s 匀速放行,用 burst 提供突发缓冲队列(超 rate 的请求排队而非立即拒,满了才拒)、nodelay 让突发请求立即处理(burst+nodelay 最常用),防高频刷接口;② limit_conn(并发连接数)——限制同一 key 的并发连接,适合下载/长连接。都是先 xxx_zone 定义规则(key 常用 $binary_remote_addr 按 IP)再在 location 应用。价值是在最前的流量入口挡掉过量请求,保护后端。口诀:limit_req 管速率(漏桶+burst+nodelay)、limit_conn 管并发连接。