当网站流量越来越大,单台后端服务器扛不住的时候,最常见的做法就是在Nginx后面挂多台应用服务器,由Nginx统一分发请求。这个分发动作依赖的就是upstream模块,而怎么分、按什么比例分、某台机器挂了怎么办,这些问题的答案都藏在权重和策略的配置里。配置写错一个参数,就可能出现一台机器被打满、其他机器全程围观的情况。

upstream基础配置与权重计算原理
先看一个最典型的带权重的upstream配置:
upstream backend {
server 192.168.1.101:8080 weight=3;
server 192.168.1.102:8080 weight=2;
server 192.168.1.103:8080 weight=1;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
这个配置里三台机器的权重分别是3、2、1,总权重是6。Nginx会按照3:2:1的比例把请求分给这三台机器,也就是每6个请求中,101机器接3个,102机器接2个,103机器接1个。如果三台机器配置相同,全部不写weight,默认weight都是1,就变成了最普通的轮询。
权重分配是平滑加权轮询算法,不是简单地连续3次都发给同一台机器。Nginx内部为每个节点维护两个值:当前权重和有效权重,每轮选择时所有节点的当前权重都加上自己的有效权重,然后挑出当前权重最大的节点,把它的当前权重减去总权重,进入下一轮。这种算法能保证高权重节点获得更多请求的同时,请求在时间维度上被打散,避免瞬时压力集中砸到同一台机器上。
实际分配权重时有个常见误区:权重不是随便拍的数字。合理的做法是按机器的CPU核数、内存大小、磁盘IO能力综合估算。比如一台16核32G的机器和一台8核16G的机器混用,权重设成2:1基本合理;但如果两台机器硬件差异不大,权重差距设得过大,弱机器虽然请求数少,每个请求的处理速度却慢很多,整体响应反而会下降。
五种负载均衡策略对比与选择
除了默认的加权轮询,upstream还支持其他几种策略,各有明确的适用边界。
第一种是默认轮询。不写任何策略指令,Nginx按权重依次分发请求。它适合后端节点处理能力相近、请求本身无状态的场景,比如纯API服务、静态资源服务,这是绝大多数项目的默认选择。
第二种就是前面说的权重分配,适合后端机器配置不统一的集群。老机器和新机器混部时,用权重把流量比例拉开,能最大化利用每台机器的容量。
第三种是ip_hash,配置方式如下:
upstream backend {
ip_hash;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
它根据客户端IP地址做哈希,同一个IP的请求固定打到同一台后端,这样可以解决session保存在单机内存里的问题。但要注意两个坑:一是大量用户走同一个出口NAT上网时,这些用户全被哈希到同一台机器,会造成流量倾斜;二是某台机器下线后,哈希结果会重新分布,部分用户的session会丢失。如果业务允许,更推荐把session放到Redis里共享,然后用默认轮询。
第四种是最少连接数策略,指令是least_conn,每次把请求分给当前活跃连接数最少的节点。它适合请求处理时长差异很大的场景,比如有的请求毫秒级返回,有的要跑几十秒的报表任务,轮询会导致慢请求堆积的机器过载,最少连接数能动态均衡真实负载。
第五种是第三方模块fair,按后端节点的响应速度分发,响应快的多分请求。它需要单独编译ngx_http_upstream_fair模块,用得相对少,而且响应速度受网络波动影响大,一般项目用least_conn就能覆盖大部分需求。
节点状态参数与健康检查
upstream里的每个server节点除了weight,还可以附加几个很实用的状态参数。看下面这个相对完整的配置:
upstream backend {
server 192.168.1.101:8080 weight=3 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 weight=2 max_fails=3 fail_timeout=30s;
server 192.168.1.103:8080 backup;
server 192.168.1.104:8080 down;
}
max_fails配合fail_timeout实现了被动健康检查:30秒内如果某个节点失败3次,Nginx会在接下来的30秒内不再把请求发给它。注意这个失败计数只在proxy_next_upstream定义的失败场景里才生效,默认是连接失败和发送请求失败,如果想把后端返回500也算失败,需要显式配置:
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_connect_timeout 3s;
proxy_read_timeout 10s;
}
这样配置后,某台后端挂了,请求会自动转发到其他健康节点,用户基本无感知。backup参数标记的节点平时不参与分流,只有当其他所有正常节点都不可用时才启用,适合放一台低配冷备机器。down参数则是手工把节点摘出集群,比直接注释配置行更清晰,方便临时维护。
被动检查的缺点是感知有延迟,刚挂掉的机器在失败次数攒够之前还会接请求。如果对可用性要求高,可以用nginx_upstream_check_module这类第三方模块做主动探测,定时向后端发健康检查请求,坏节点秒级摘除,恢复后自动加回。
总结与实践建议
策略选择的思路可以简化成一句话:无状态服务用默认加权轮询,机器配置不齐就配weight,请求耗时差异大用least_conn,必须粘滞会话才考虑ip_hash。绝大多数业务用前两种就够用了。
另外提醒两点容易忽略的细节。一是修改upstream里的节点后需要执行nginx -s reload才能生效,reload是平滑的,不会断开已有连接;二是keepalive配置建议加上,在upstream块内写一行keepalive 32,并在location里配置proxy_http_version 1.1和proxy_set_header Connection空字符串,能让Nginx与后端之间复用长连接,减少每次请求的TCP握手开销,高并发场景下提升明显。
Nginx upstream负载均衡权重分配修改时间:2026-09-16 21:20:47