结论:服务器负载均衡最通用的配置方式是在 Nginx 里定义 upstream 组并 proxy_pass 转发到该组,四行配置即可生效:轮询适合同构机器、加权轮询应对性能差异、ip_hash 实现简单会话保持、least_conn 适合长连接业务。生产环境必须再叠加健康检查、超时控制与真实客户端 IP 透传三件事。
负载均衡(Load Balancing,LB)的作用是把流量按规则分摊到多台后端服务器(Upstream Server),既提升并发能力,又在某台机器挂掉时自动把它摘除,从而在用户无感知的情况下实现高可用。截至 2026 年,中小规模业务的首选依然是 Nginx(七层)或 HAProxy(四层/七层混合),只有当并发达到十万级、对转发性能有极致要求时才需要引入 LVS(DR 模式)或云厂商的 CLB。
四层负载均衡和七层负载均衡有什么区别?
区别在于它"看懂"到网络协议的哪一层。四层负载均衡工作在传输层(TCP/UDP),只看 IP 和端口就转发,性能极高但看不懂请求内容;七层负载均衡工作在应用层(HTTP/HTTPS),能解析 URL、Header、Cookie,因此可以做基于路径的路由、灰度发布、请求改写,代价是 CPU 开销更大。
| 对比维度 | 四层负载均衡(LVS/CLB 四层) | 七层负载均衡(Nginx/HAProxy) |
|---|---|---|
| 工作层级 | OSI 第 4 层(TCP/UDP) | OSI 第 7 层(HTTP/HTTPS) |
| 转发依据 | 目标 IP + 端口 | URL、Host、Header、Cookie |
| 单机性能 | 极高,可达百万并发 | 万级到十万级并发 |
| 是否解析报文内容 | 否 | 是,可读取和修改 Header |
| 是否可做路径路由 | 否 | 可以,/api 和 /static 走不同后端 |
| 是否需要解析 SSL | 通常直接透传 | 需要卸载证书或用 TLS 透传 |
| 典型代表 | LVS(DR/NAT/TUN)、DPDK、云 CLB | Nginx、HAProxy、Envoy、Traefik |
实际架构里二者常常叠着用:最外层用 LVS 或云 CLB 扛住海量连接,第二层用 Nginx 做七层的精细路由,这就是经典的"LVS + Nginx"双层架构。
Nginx upstream 的四种调度算法怎么选?
Nginx 默认使用加权轮询(Weighted Round Robin),绝大多数场景无需改动。只有当后端机器性能不一致、或业务依赖长连接、或需要会话保持时,才需要显式指定其他算法。
| 算法 | 写法 | 适用场景 | 注意事项 |
|---|---|---|---|
| 轮询(默认) | 不写或 round_robin | 后端机器配置相同的无状态服务 | 请求按顺序轮流分配,最公平 |
| 加权轮询 | server x.x.x.x weight=3; | 新老机器混跑,性能相差数倍 | weight 默认 1,数值越大分到越多请求 |
| 最少连接 | least_conn; | 长连接、请求耗时差异大(如文件上传) | 把请求给当前连接数最少的节点 |
| IP 哈希 | ip_hash; | 没有 Redis 又要保持会话的旧系统 | 按客户端 IP 前 3 段哈希,同 IP 固定落到同一台 |
| 一致性哈希 | hash $request_uri consistent; | 缓存类场景,希望提高缓存命中率 | Nginx 1.7.2+ 支持 consistent 参数 |
一份生产可用的 Nginx 负载均衡配置:
upstream backend_api {
least_conn;
server 10.0.0.11:8080 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.0.12:8080 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.13:8080 weight=1 backup; # 备用机,平时不接流量
keepalive 64; # 与后端保持长连接,显著降低握手开销
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend_api;
# 透传真实客户端信息,后端日志才能看到真实 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;
# 超时控制,避免后端卡死拖垮 Nginx 连接数
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 使用 keepalive 必须启用 HTTP/1.1 并清空 Connection 头
proxy_http_version 1.1;
proxy_set_header Connection "";
# 后端返回 5xx 或超时时自动切换到下一台,最多重试 2 次
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 10s;
}
# 健康检查端点:静态返回,不打到后端
location = /healthz {
access_log off;
default_type text/plain;
return 200 "ok\n";
}
}改完配置先语法检查再平滑重载,切勿直接 restart:
nginx -t
systemctl reload nginx # 或者 nginx -s reload
# 观察后端节点是否真的被轮询到(在每台后端看访问日志)
tail -f /var/log/nginx/access.log | grep healthz
# 验证摘除机制:停掉 10.0.0.11 后连续请求,确认不再返回 502
for i in $(seq 1 20); do curl -s -o /dev/null -w "%{http_code}\n" http://api.example.com/; done健康检查与故障摘除怎么做得更快?
开源版 Nginx 的健康检查是"被动式"的:只有真实请求打到某个节点失败累计到 max_fails 次,才在 fail_timeout 时间内把它标记为不可用。这意味着最快也要几秒才能摘除故障节点,而且期间会有部分用户请求失败。
被动检查的关键参数组合:
max_fails=3 fail_timeout=30s:30 秒内失败 3 次,则该节点被摘除 30 秒。proxy_next_upstream:定义哪些错误需要"换一台重试",一定要包含error timeout,否则后端超时会直接返回给用户。proxy_connect_timeout 5s:这个参数最容易被忽略。TCP 连接超时不设的话,遇到后端 host 宕机会等足系统默认的 60 秒以上,瞬间耗尽 Nginx 的 worker 连接。
如果需要更灵敏的主动探测,可选三条路:使用 Nginx Plus 的 health_check 指令、改用 HAProxy(开源版自带主动检查)、或用 tengine/nginx_upstream_check_module 第三方模块。
HAProxy 适合什么场景?怎么写配置?
HAProxy 的优势是同时支持四层(mode tcp)和七层(mode http),且开源版就自带完善的主动健康检查、连接数限制、ACL 规则和统计页面。它是 MySQL、Redis、消息队列等长连接服务做负载均衡的事实标准。
一份 HAProxy 配置示例(/etc/haproxy/haproxy.cfg):
global
log /dev/log local0 info
maxconn 65535
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
timeout connect 5s
timeout client 30s
timeout server 30s
frontend http_in
bind *:80
default_backend web_pool
backend web_pool
balance roundrobin
# 主动健康检查:每 2 秒发一次请求,连续 3 次 2xx/3xx 才算健康
option httpchk GET /healthz HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
server web01 10.0.0.11:8080 check inter 2s fall 3 rise 2 weight 3
server web02 10.0.0.12:8080 check inter 2s fall 3 rise 2 weight 2
frontend stats_in
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:StrongPass2026
# MySQL 四层负载均衡示例(读流量分摊到从库)
listen mysql_read
bind *:3307
mode tcp
balance leastconn
option tcp-check
server db01 10.0.0.21:3306 check port 3306 inter 3s fall 3 rise 2
server db02 10.0.0.22:3306 check port 3306 inter 3s fall 3 rise 2启动并验证:
haproxy -c -f /etc/haproxy/haproxy.cfg # 语法检查
systemctl enable --now haproxy
curl -u admin:StrongPass2026 http://127.0.0.1:8404/stats\;csv | head -20
# 摘除/恢复某个节点(需开启 stats socket)
echo "disable server web_pool/web01" | socat stdio /run/haproxy/admin.sock
echo "enable server web_pool/web01" | socat stdio /run/haproxy/admin.sock会话保持(Session 保持)怎么做最稳?
最稳的做法是"不要会话保持",把 Session 外置到 Redis,从而彻底避免这个问题。因为任何形式的会话保持都会破坏负载均衡的均匀性:某些用户特别活跃时,它们固定的那台机器会明显过热;而该机器宕机后,这些用户的 Session 又会全部丢失。
如果业务确实改造不了,按优先级从高到低选这三种方案:
- Redis 集中存储 Session(首选):应用配置 Session 到 Redis 集群,Nginx 无需任何特殊配置。
- Cookie 插入:HAProxy 用
cookie SERVERID insert indirect nocache让 LB 自己写入后端标识 Cookie,比 ip_hash 更精准。 ip_hash/hash $cookie_jsessionid(兜底):改动最小,但存在移动端 NAT 出口导致大量用户偏落到同一台的问题。
upstream legacy_app {
ip_hash; # 兜底方案:按客户端 IP 分配
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
upstream session_app {
hash $cookie_jsessionid consistent; # 按应用层 Session ID 哈希,优于 ip_hash
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}常见误区 / 排错提示
- 误区一:后端看到的全是 Nginx 的 IP。 忘记配置
X-Real-IP与X-Forwarded-For,导致应用日志、风控、限流全部失效。此时还要在后端 Nginx/PHP 里启用real_ip_header X-Forwarded-For; set_real_ip_from 10.0.0.0/8;才能真正取到真实 IP。 - 误区二:upstream 里用域名不加 resolver。 直接写
server api.internal.com:8080;时,Nginx 只在启动时解析一次,后端 IP 变了它不会更新。必须补resolver 10.0.0.2 valid=30s ipv6=off;,或使用 Nginx Plus 的resolve参数。 - 误区三:以为配了负载均衡就高可用了。 那台跑 Nginx 的机器本身成了新的单点。必须给它配 Keepalived VIP 双机热备,或直接使用云厂商托管的负载均衡实例。
- 误区四:把
proxy_next_upstream配得太激进。 对非幂等的 POST 请求(下单、支付)重试会导致重复扣款。正确做法是只对 GET 重试,或在proxy_next_upstream中排除http_500,由业务侧保证幂等。 - 排错:返回 502 Bad Gateway。 检查后端端口是否监听(
ss -lntp | grep 8080)、防火墙/安全组是否放行内网端口、SELinux 是否阻止 Nginx 发起外部连接(setsebool -P httpd_can_network_connect 1)。 - 排错:返回 504 Gateway Timeout。 是后端处理太慢而非网络问题。适当调大
proxy_read_timeout,同时用perf或慢查询日志排查后端为什么慢。
常见问题(FAQ)
一台服务器上 Nginx 配负载均衡有意义吗?
结论:有意义,但主要是用于本机多实例(多端口)的负载分摊与故障隔离。比如一台 16 核机器跑 4 个 Java 实例(8081-8084),Nginx 把请求分给它们,能更好地利用多核、避免单实例 GC 停顿影响全部请求,还能做到滚动重启不中断服务。但它解决不了机器级的单点故障。
Nginx 和 HAProxy 该选哪个?
结论:主要做 HTTP 转发且团队熟悉 Nginx 就选 Nginx,需要 TCP 转发或更精细的健康检查就选 HAProxy。Nginx 的优势是同时身兼 Web 服务器、反向代理、静态资源服务、TLS 终结于一身,运维对象更少;HAProxy 在四层转发、连接数控制、细粒度 ACL 和统计面板上更强,尤其适合 MySQL/Redis 这类场景。
负载均衡需要多大的机器配置?
结论:七层 Nginx 转发通常不是瓶颈,2 核 4 GB 就能扛住数千 QPS。真正的瓶颈往往是连接数与带宽:默认 worker_connections 1024 下,理论并发 = worker_processes × 1024,建议调整为 worker_connections 65535 并同步调大系统 ulimit -n。另外别忘了 net.ipv4.ip_local_port_range,高位端口不够时会报 "Cannot assign requested address"。
怎么做 HTTPS 卸载(SSL Termination)?
结论:把证书配在负载均衡层,后端走明文 HTTP,这是最主流的做法。好处是证书只需维护一份、后端不消耗加解密 CPU、且 LB 能看到明文请求以便做路由和 WAF 检测。代价是内网链路必须可信,因此 VPC 内的后端端口绝不能暴露到公网。配置上把 listen 443 ssl; 与证书路径写在 LB 的 server 块里,proxy_pass 仍指向 http://backend_api。
加了新后端节点,现有连接会迁移过去吗?
结论:不会自动迁移已有连接,只影响新连接。轮询是"按请求"分配的,长连接(WebSocket、keepalive)一旦建立就固定在那台机器上,这是 ip_hash 之外的另一种"隐性粘滞"。如果希望平滑重分布,可以在低峰期 reload Nginx 或重启后端让其连接重建;不要期待配置一改立即均摊。
后端机器性能不一样,怎么按比例分配流量?
结论:用 weight 加权轮询,权重比例按实测 QPS 能力设定。例如老机器 4 核、新机器 8 核,可设 weight=1 与 weight=2。更精细的做法是先用压测工具(如 wrk)测出单机极限 QPS,再按该数值定权重,而不是简单按 CPU 核数估算——因为磁盘 IO 和内存带宽常常才是真正的限制因素。
企业QQ咨询




