应使用 geo + map 实现 ip 段分流:geo 精确匹配客户端 ip 归类,map 将类别映射为 upstream 名称,再通过 proxy_pass 动态转发;不可依赖 upstream weight 或 if/set,复杂动态权重需 openresty。

直接在 upstream 里设 weight 无法识别 IP 段,Nginx 的 weight 参数只作用于后端服务器,不感知客户端来源。要实现“对特定 IP 段用户分配更高资源”,必须结合请求特征做动态路由,而不是单纯调高某台 server 的 weight。
用 map + upstream 分组实现 IP 段分流
这是最常用、无需额外组件的方案:先按客户端 IP 归类,再把不同类别导向不同权重配置的 upstream。
- 在 http 块中定义 IP 段映射规则,例如将 192.168.10.0/24 和 2001:db8::/64 标记为 high-priority
- 为高优 IP 组和普通 IP 组分别创建独立 upstream,各自设置合理权重(如 high-priority 组内 server weight=5/3/2,default 组用 weight=1/1/1)
- 在 location 中通过 proxy_pass http://$upstream_group; 动态转发
配合 geo 指令更精准识别 IP 范围
map 对 CIDR 支持有限,geo 指令专为 IP 匹配设计,推荐用于复杂网段判断:
- geo $client_priority { default 0; 192.168.10.0/24 1; 10.0.0.0/8 1; }
- 再用 map 把 $client_priority 转成 upstream 名称(如 $upstream_group),避免在 proxy_pass 中写逻辑
- 注意 geo 变量在 server 块外定义,且匹配顺序从上到下,需把精确网段放前面
避免常见错误配置
这类需求容易踩坑,尤其要注意:
- 不能在同一个 location 里写多个 proxy_pass;Nginx 不允许多个转发目标混用
- ip_hash 和 weight 同时启用时,weight 只在节点失效后参与 fallback,不影响哈希绑定——所以别指望 ip_hash + weight 能给某段 IP “加权”
- 不要试图用 if 判断 $remote_addr 再 set $upstream —— if 在 location 中限制多,且 proxy_pass 不支持变量拼接 host(除非用 resolver + 变量域名)
进阶:需要实时调整权重就上 OpenResty
如果高优 IP 段的流量波动大,或需根据后端延迟/错误率动态升降权重,纯 Nginx 做不到。这时得用 OpenResty:
- 在 balancer_by_lua_block 中读取共享字典里的指标(比如该 IP 段最近 1 分钟平均 RT)
- 按公式算出临时权重,调用 balancer.set_current_peer() 指向最优节点
- 搭配 Prometheus 定时上报后端状态,维持字典数据新鲜度











