单台服务器扛不住的时候,第一反应是升级配置,但升级总有上限。横向扩展(加机器分摊流量)才是终极方案,而 Nginx 就是最常用的流量分发入口。
这篇讲 Nginx 负载均衡的完整配置:upstream 池、负载策略、健康检查、会话保持。配置可直接用于生产。
需要云服务器可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏快速部署。
一、负载均衡基础架构
用户 → Nginx(负载均衡器) → 后端1 (10.0.0.1:8080)
→ 后端2 (10.0.0.2:8080)
→ 后端3 (10.0.0.3:8080)Nginx 收请求,按策略分给后端。后端挂了自动剔除,加机器自动加入。
二、upstream 基础配置
http {
# 定义后端服务器池
upstream backend {
server 10.0.0.1:8080 weight=3; # weight 权重,默认1
server 10.0.0.2:8080 weight=2;
server 10.0.0.3:8080 weight=1;
# 备用机: 主都挂了才用
server 10.0.0.4:8080 backup;
# 标记不参与负载
server 10.0.0.5:8080 down;
keepalive 32; # 保持和后端的长连接,减少握手
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
# 传递真实 IP 给后端(关键,后面要用)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}
}权重分配场景:后端1 是新机器(8核),后端2 是旧机器(4核)→ weight=2 和 weight=1,按能力分摊。
三、五种负载策略
1. 轮询(默认)
每个请求按顺序分给下一台。适合后端性能一致的场景。
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}2. 权重轮询
upstream backend {
server 10.0.0.1:8080 weight=5;
server 10.0.0.2:8080 weight=1;
}
# 5:1 分配,机器强的多干活3. IP Hash(会话保持)
同一个 IP 的请求总是落到同一台后端——用户 session 不用共享:
upstream backend {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}适合:后台管理系统、session 存在本地的老应用。缺点:某 IP 流量大会不均;后端增减会重新分配。
4. 最少连接
请求分给当前连接数最少的后端:
upstream backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}适合:请求处理时间差异大的场景(有的请求 10ms,有的 3s)。
5. 一致性 Hash
upstream backend {
hash $request_uri consistent;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}相同 URL 总是落到同一台——缓存命中率最大化。适合图片站、静态内容分发。
策略选择表
| 场景 | 策略 |
|---|---|
| 无状态 API、同配置机器 | 轮询或权重 |
| Session 在本地 | ip_hash |
| 请求处理时间不均 | least_conn |
| 缓存型内容(图片) | hash consistent |
| 新老机器混用 | weight |
四、健康检查:自动剔除坏后端
Nginx 开源版没有主动健康检查(Plus 版才有),用被动机制 + max_fails:
upstream backend {
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
# 被动检查参数:
# max_fails=3 30 秒内失败 3 次就标记不可用
# fail_timeout=30s 标记后 30 秒内不再分流量给它,之后试探恢复
}被动检查的问题:只有真有请求过去才知道它挂了。想要主动检查,两个方案:
方案 A:nginx_upstream_check_module(需重编译 Nginx,淘宝 Tengine 自带)
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
check interval=3000 rise=2 fall=5 timeout=2000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}方案 B:定时任务剔除(不动 Nginx,适合开源版)
#!/bin/bash
# 后端健康检查,挂了就从 upstream 里摘掉
BACKENDS="10.0.0.1:8080 10.0.0.2:8080"
UPSTREAM_CONF="/etc/nginx/conf.d/upstream.conf"
> "$UPSTREAM_CONF.tmp"
echo "upstream backend {" >> "$UPSTREAM_CONF.tmp"
for b in $BACKENDS; do
ip=${b%:*}; port=${b#*:}
if curl -sf -m 2 "http://$ip:$port/health" > /dev/null 2>&1; then
echo " server $b max_fails=3 fail_timeout=30s;" >> "$UPSTREAM_CONF.tmp"
else
echo " # 剔除: $b 健康检查失败 $(date)" >> "$UPSTREAM_CONF.tmp"
fi
done
echo "}" >> "$UPSTREAM_CONF.tmp"
if ! diff -q "$UPSTREAM_CONF" "$UPSTREAM_CONF.tmp" > /dev/null; then
mv "$UPSTREAM_CONF.tmp" "$UPSTREAM_CONF"
nginx -t && systemctl reload nginx
ficrontab -e
* * * * * /opt/scripts/upstream-health.sh后端必须提供 /health 接口(返回 200 即可):
// PHP 版健康检查
<?php
header('Content-Type: application/json');
echo json_encode(['status' => 'ok', 'db' => checkDb()]);五、会话保持的三种方案
负载均衡后,session 放哪?
| 方案 | 做法 | 适用 |
|---|---|---|
| ip_hash | 同 IP 固定后端 | 快速方案,后端增减有感觉 |
| session 共享 | Redis/Memcached 存 session | 最佳实践,推荐 |
| sticky cookie | Nginx 按 cookie 路由 | 需要三方模块 |
Redis 共享 session(PHP 示例):
; php.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=Redis密码"这样任何后端都能读到 session,后端随便加减,用户无感知。
六、完整生产配置模板
# /etc/nginx/conf.d/lb.conf
# 后端池
upstream app_backend {
least_conn; # 按场景换策略
server 10.0.0.1:8080 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.3:8080 backup max_fails=3 fail_timeout=30s;
keepalive 32;
}
# 限流区(防单 IP 打爆后端)
limit_req_zone $binary_remote_addr zone=api:10m rate=50r/s;
server {
listen 443 ssl http2;
server_name api.example.com;
# 访问日志带后端信息(排障要知道请求分给谁了)
log_format lb '$remote_addr - [$time_local] "$request" '
'$status $upstream_addr rt=$request_time '
'urt=$upstream_response_time';
access_log /var/log/nginx/lb.log lb;
location / {
limit_req zone=api burst=100 nodelay;
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection ""; # keepalive 必须
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 3s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 缓冲设置(慢后端不拖垮 Nginx)
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 16 8k;
}
# 健康检查端点(给上面的健康脚本用)
location = /lb-status {
access_log off;
return 200 "ok";
}
}七、排障:看请求分给谁了
# 1. 日志里的 $upstream_addr 显示实际转发目标
tail -f /var/log/nginx/lb.log
# 10.0.0.1:8080: 10.0.0.1:8080, 10.0.0.2:8080 格式: 请求IP: 尝试的后端列表
# 多个地址 = 发生了重试(第一个挂了)
# 2. 502 常见原因
# - 后端全挂(看 upstream_addr 和 error.log)
# - 后端响应太慢(proxy_read_timeout)
# - keepalive 配置不一致导致连接被拒
# 3. 测试各后端直连
curl -I http://10.0.0.1:8080/health
curl -I http://10.0.0.2:8080/health八、常见问题
Q:502 Bad Gateway?
后端挂了或连不上。看 error.log 里的 upstream 信息,逐个 curl 后端健康接口。
Q:加了 keepalive 反而 502?proxy_set_header Connection ""; 和 proxy_http_version 1.1; 必须配对设置,缺一个就会出现连接被后端关闭。
Q:后端 IP 变了要改配置?
用 DNS 域名做 upstream(Nginx 会按 resolve 参数定时解析),或者上服务发现(Consul)。小规模直接改配置 reload 也行。
Q:一台 Nginx 会不会成为单点?
会。高可用方案:两台 Nginx + Keepalived 抢 VIP,或者上云厂商的 LB 服务(ALB/CLB),它们自带健康检查和高可用。
Q:游戏服能用 Nginx 负载均衡吗?
不能!游戏服是长连接 UDP/TCP 有状态协议,不是 HTTP。游戏服的「负载均衡」是玩家分流(不同服不同端口),不是 LB。多游戏共存见多游戏共存配置。
Q:NAT 型服务器怎么做多机负载?
NAT 机型之间没有内网,回源要经过公网,延迟和带宽都吃亏。要做 LB,选有内网的产品,或者干脆单机扛 + CDN 分摊。
小结
Nginx 负载均衡核心三件套:upstream 池 + 合理策略 + 健康检查。无状态应用轮询/最少连接,有 session 用 ip_hash 或 Redis 共享,后端必须提供 /health 接口。配好日志里的 $upstream_addr,排障时一眼看出请求分给了谁。
更多网站架构内容见财富云计算知识库:Nginx 配置、反向代理、CDN、性能优化全系列。需要云服务器可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上。
延伸阅读
- 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
- 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
- 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
- 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
- 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
- RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
- 短链接服务搭建:Shlink 自托管,链接数据自己掌握
- 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道

[...]# 用 last/permanent 分清语义,配 error_log info 看跳转链完整 Web 防护见网站常见漏洞与基础防护和WAF 规则实战。七、速查表需求写法伪静态try_files $uri $uri/ /index.php?$query_string;HTTP→HTTPSreturn 301 https://$host$request_uri;www 跳主域return 301 h[...]
2026-10-15 回复
[...]netsh advfirewall firewall add rule name="GameRange" dir=in action=allow protocol=UDP localport=26901-26903完整的 Windows 环境准备(远程桌面连接、运行库安装、SteamCMD 用法、开机自启、8 个常见坑)见:《Windows 云服务器开服通用前置教程》→ htt[...]
2026-10-18 回复
[...]./discourse-setupapp.yml 里配好域名、SMTP(Discourse 强依赖邮件,注册验证、通知全走邮件,必须先配好发信,见邮件退信与 SPF/DKIM/DMARC 配置)。Discourse 的管理后台是它的精髓:信任等级自动权限、反垃圾评分、敏感词、话题合并——社区做大了,这些工具能省掉两个运营。四、社区运营的三条硬功夫技术只是上半场,社区死活在下半场:冷启动:前 100[...]
2026-10-18 回复