在 nginx 中限制后端代理的并发请求数,核心做法是结合 limit_req_zone 和 proxy_pass。通过定义共享内存区域来统计请求频率,并在 location 块中使用 limit_req 指令将该限制应用到代理请求上,从而保护后端服务不被过多并发请求压垮。

如何配置共享内存区域以记录请求状态
要启用并发限制,必须在 http 上下文中使用 limit_req_zone 指令创建一个共享内存区域。该区域用于存储请求的状态信息,如时间戳和计数。需要指定一个唯一的名称、内存大小以及用于识别客户端的键(通常是 $binary_remote_addr)。这个步骤是后续所有限制生效的基础,它确保了 Nginx 能够跨多个 worker 进程一致地追踪请求。

worker_processes auto;
events {
worker_connections 1024;
}
http {
# 定义共享内存区域,名为 'one',大小为 10m
# key 为客户端 IP,rate 为每秒允许 1 个请求
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
listen 80;
server_name example.com;
location /api/ {
# 应用限制,burst 允许突发处理 5 个请求
limit_req zone=one burst=5 nodelay;
# 代理到后端服务
proxy_pass http://backend_server;
}
}
}
上述配置中,zone=one:10m 创建了一个名为 one 的区域,分配 10MB 内存。rate=1r/s 定义了平均速率。当请求进入 /api/ 路径时,Nginx 会检查该区域的计数器。如果请求超过设定速率,将根据 burst 参数决定是直接拒绝还是排队处理。
burst 和 nodelay 参数对并发处理的影响是什么
burst 和 nodelay 参数决定了当请求超过基础速率时的具体行为。burst 设置了一个队列长度,允许在超出速率限制的瞬间,将额外的请求放入队列等待处理,而不是立即返回错误。nodelay 选项则指示 Nginx 不延迟处理这些突发请求,而是立即将它们发送给后端,只要它们仍在 burst 允许的范围内。如果没有 nodelay,队列中的请求会被延迟发送,直到速率槽位空闲出来。

# 场景 A: 有 nodelay limit_req zone=one burst=5 nodelay; # 结果: 前 6 个请求(1个基准 + 5个突发)立即被处理,第 7 个开始返回 503 # 场景 B: 无 nodelay limit_req zone=one burst=5; # 结果: 前 1 个请求立即处理,剩余 5 个请求被延迟发送,第 7 个开始返回 503
在实际应用中,选择是否使用 nodelay 取决于后端服务的处理能力。如果后端能快速处理突发流量,nodelay 能提供更好的用户体验;如果后端对瞬时压力敏感,去掉 nodelay 可以让请求更平滑地进入后端,避免后端因瞬间过载而崩溃。
当请求超过限制时,Nginx 默认返回什么状态码
当请求超过 limit_req 设定的限制且无法放入 burst 队列时,Nginx 默认返回 HTTP 503 Service Temporarily Unavailable 状态码。这是标准的限流响应,表明服务器暂时无法处理请求。可以通过 limit_req_status 指令自定义这个状态码,例如改为 429 Too Many Requests,以便前端或客户端能更准确地识别限流情况。
http {
# 自定义限流返回的状态码为 429
limit_req_status 429;
server {
location /api/ {
limit_req zone=one burst=5;
proxy_pass http://backend_server;
}
}
}
修改状态码后,客户端可以根据 429 状态码实现重试逻辑或显示友好的提示信息,而不是通用的 503 错误页面。这对于构建健壮的分布式系统非常重要,因为它允许客户端根据具体的错误类型采取不同的应对策略。











