在 nginx 中设置请求频率限制,核心做法是先在 http 块中使用 limit_req_zone 指令定义共享内存区域和计费键,然后在 server 或 location 块中使用 limit_req 指令启用该区域并指定速率。这样做会拦截超出设定频率的请求,并根据配置返回 503 错误。

如何定义限流区域与选择计费键
要定义限流区域,需在 nginx.conf 的 http 上下文中添加 limit_req_zone 指令。该指令需要三个关键参数:用于区分不同用户的变量(如 $binary_remote_addr)、共享内存的大小以及平均请求速率。选择正确的计费键决定了限流的粒度,使用客户端 IP 地址是最常见的做法,能有效防止单个用户滥用服务。

http {
# 定义名为 'one' 的区域,使用客户端 IP 作为键
# 大小 10m,允许平均每秒 1 个请求 (rate=1r/s)
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
location /search {
# 应用 'one' 区域的限流规则
limit_req zone=one burst=5 nodelay;
proxy_pass http://backend;
}
}
}
在上述配置中,zone=one:10m 分配了 10MB 的共享内存,足以存储约 16 万个 IP 地址的状态。rate=1r/s 定义了令牌桶的填充速度。当请求到达时,Nginx 会检查该 IP 对应的令牌是否充足。如果不足,请求将被排队或直接拒绝。这种机制确保了后端服务不会因为突发流量而崩溃。
如何处理突发流量与延迟策略
处理突发流量的关键在于 limit_req 指令中的 burst 和 nodelay 参数。burst 设置了允许排队等待的最大请求数,而 nodelay 控制这些排队的请求是否立即处理。如果不加 nodelay,排队中的请求会按照定义的速率均匀分布地处理;加上后,它们会立即被处理,从而缓解用户的感知延迟。

# 仅使用 burst,不加 nodelay limit_req zone=one burst=5; # 使用 burst 并立即处理排队请求 limit_req zone=one burst=5 nodelay;
当配置为 burst=5 且没有 nodelay 时,如果当前有 6 个并发请求(1 个正在处理 + 5 个排队),前 1 个立即响应,其余 5 个会被放入队列,并按每秒 1 个的速度依次处理。这意味着第 6 个请求可能需要等待几秒才能被后端处理。如果添加了 nodelay,这 5 个排队请求会瞬间全部发送给后端,后端需要能够承受这种瞬时压力。对于大多数 Web 应用,推荐使用 nodelay 以保证用户体验,但需确保后端能处理突发峰值。
当请求超过限制时会返回什么状态码
当请求频率超过限制且无法进入缓冲队列时,Nginx 默认会返回 HTTP 503 Service Temporarily Unavailable 状态码。可以通过 limit_req_status 指令修改这个行为,例如将其改为 429 Too Many Requests,以便前端能更准确地识别这是限流导致的错误而非服务器内部故障。
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
# 将超限返回的状态码改为 429
limit_req_status 429;
server {
location /api {
limit_req zone=one burst=2;
return 200 "OK";
}
}
}
在实际开发中,返回 429 状态码更符合 RESTful API 的规范。前端代码可以监听 429 响应,并提示用户“操作过于频繁,请稍后再试”。此外,还可以结合 error_page 指令,将 503 或 429 错误重定向到一个自定义的错误页面,提升用户体验。需要注意的是,修改状态码不会影响限流逻辑本身,只是改变了对外展示的 HTTP 响应代码。











