Nginx轮询负载均衡中限流应作用于请求进入upstream前或各后端节点入口;优先用limit_req实现上游前限流,其次用map+变量为各server单独限流,仅特殊需求才开发C模块,并需结合健康检查防雪崩。

在 Nginx 的轮询(round-robin)负载均衡中集成自定义限流模块,核心思路是:**限流不直接作用于 upstream 轮询逻辑本身,而是作用于请求进入 upstream 之前或每个后端节点的入口处**。Nginx 官方限流机制(如 limit_req)已足够灵活,通常无需编写 C 模块;若确有特殊策略(如按用户标签、动态阈值、与外部系统联动),才需开发自定义模块。以下是实用路径:
用原生 limit_req 实现上游前限流(推荐)
这是最常用、最稳定的方式。在 http 或 server 块中定义限流区,再在 location 中应用,控制发往整个 upstream 的请求速率:
http {
# 定义共享内存区:每秒最多 100 个请求,突发容量 50
limit_req_zone $binary_remote_addr zone=perip:10m rate=100r/s;
<pre class='brush:php;toolbar:false;'>upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# 默认 round-robin,无需显式写 balance=round-robin
}
server {
location /api/ {
# 对每个客户端 IP 限流,再转发给 upstream
limit_req zone=perip burst=50 nodelay;
proxy_pass http://backend;
}
}}
✅ 优点:零编译、热重载、支持日志记录(limit_req_log_level)、可组合(如配合 limit_conn)。
为每个 upstream server 单独限流(精细化控制)
若需对不同后端节点施加不同限流策略(例如旧节点处理能力弱),可用 split_clients 或变量 + map 动态选择限流区,再结合 proxy_next_upstream 处理被限流的失败:
- 用
map根据 $upstream_addr 或自定义变量映射到不同限流 zone - 在
location中使用limit_req zone=$chosen_zone - 配置
proxy_next_upstream error timeout http_503,让被限流返回 503 的请求自动重试下一个 upstream server
⚠️ 注意:Nginx 不允许在 upstream 块内直接写 limit_req,必须在 location 层通过变量间接绑定。
开发自定义限流模块(仅当原生不满足)
若需对接 Redis 计数、调用 gRPC 鉴权服务、或实现滑动窗口等高级算法,才考虑 C 模块。关键步骤包括:
- 实现
ngx_http_handler_pt类型的 handler,在NGX_HTTP_ACCESS_PHASE阶段介入 - 从请求中提取 key(如
$arg_token或$http_x_user_id) - 调用自定义逻辑(如读写共享内存、发 HTTP 请求到限流服务)判断是否放行
- 返回
NGX_OK(放行)、NGX_HTTP_SERVICE_UNAVAILABLE(503)或NGX_DECLINED(交由下一模块) - 在配置中注册指令,例如
my_rate_limit on|off;,并支持 zone 参数
? 提示:优先复用 Nginx 的 ngx_slab_pool_t 共享内存管理,避免自己实现锁和计数器;调试时开启 error_log /path/debug.log debug; 查看模块执行流程。
限流与健康检查协同(防雪崩)
单纯限流不能替代节点健康感知。建议搭配:
-
health_check interval=3 fails=2 passes=2;(需 stream 或 http upstream health check 模块) - 用
proxy_next_upstream_tries 2;控制最大重试次数 - 将限流触发的 503 记录到自定义日志,用于后续分析流量分布异常
这样即使某台后端因限流频繁返回 503,健康检查也能及时将其摘除,避免轮询持续打到“假性过载”节点。


















