服务器负载均衡怎么配置

结论:服务器负载均衡最通用的配置方式是在 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、云 CLBNginx、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 负载均衡配置:

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:

bash
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):

conf
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

启动并验证:

bash
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 又会全部丢失。

如果业务确实改造不了,按优先级从高到低选这三种方案:

  1. Redis 集中存储 Session(首选):应用配置 Session 到 Redis 集群,Nginx 无需任何特殊配置。
  2. Cookie 插入:HAProxy 用 cookie SERVERID insert indirect nocache 让 LB 自己写入后端标识 Cookie,比 ip_hash 更精准。
  3. ip_hash / hash $cookie_jsessionid(兜底):改动最小,但存在移动端 NAT 出口导致大量用户偏落到同一台的问题。
nginx
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 和内存带宽常常才是真正的限制因素。