Nginx 负载均衡
大约 10 分钟约 3053 字
Nginx 负载均衡
简介
Nginx 是高性能的反向代理和负载均衡服务器,通过 upstream 模块将客户端请求分发到多台后端服务器。Nginx 支持多种负载均衡算法、健康检查、SSL 终止和会话保持等功能,能够有效提升应用的可用性和吞吐量,是构建高可用 Web 架构的核心组件。
特点
Upstream 配置
基本负载均衡
# /etc/nginx/conf.d/upstream.conf
# 基本轮询(默认)
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 加权轮询
upstream backend_weighted {
server 192.168.1.10:8080 weight=5;
server 192.168.1.11:8080 weight=3;
server 192.168.1.12:8080 weight=2;
}
# IP Hash(会话保持)
upstream backend_iphash {
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
# 最少连接数
upstream backend_leastconn {
least_conn;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 带权重的最少连接
upstream backend_wlc {
least_conn;
server 192.168.1.10:8080 weight=5;
server 192.168.1.11:8080 weight=3;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
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;
}
}算法对比
| 算法 | 指令 | 适用场景 |
|---|---|---|
| 轮询(默认) | 无需指定 | 后端服务器性能相近 |
| 加权轮询 | weight=N | 服务器性能不均 |
| IP Hash | ip_hash | 需要会话保持 |
| 最少连接 | least_conn | 请求处理时间差异大 |
| 普通 Hash | hash $request_uri | 基于 URI 的缓存分流 |
| 随机 | random | 简单场景,减少一致性开销 |
负载均衡算法详解
Hash 与一致性 Hash
# 基于 URI 的 Hash(缓存友好)
upstream backend_uri {
hash $request_uri consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 基于 Cookie 的会话保持(需要 nginx-sticky-module)
# upstream backend_sticky {
# sticky cookie srv_id expires=1h domain=.example.com path=/;
# server 192.168.1.10:8080;
# server 192.168.1.11:8080;
# }
# 基于自定义 Header 的分流
upstream backend_custom {
hash $http_x_tenant_id consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}加权与备份服务器
upstream backend_full {
# 主服务器
server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 weight=3 max_fails=3 fail_timeout=30s;
# 备份服务器(仅在所有主服务器不可用时启用)
server 192.168.1.20:8080 backup;
server 192.168.1.21:8080 backup;
# 保持长连接
keepalive 32;
keepalive_requests 1000;
keepalive_timeout 60s;
}健康检查
被动健康检查
upstream backend_passive {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass http://backend_passive;
# 连接超时
proxy_connect_timeout 5s;
# 读取超时
proxy_read_timeout 30s;
# 发送超时
proxy_send_timeout 30s;
# 下次重试(请求失败时尝试下一台服务器)
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
}
}主动健康检查(Nginx Plus 或第三方模块)
# 使用 nginx_upstream_check_module(Tengine 内置)
upstream backend_active {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
# 主动健康检查
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "HEAD /health HTTP/1.0\r\nHost: api.example.com\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
# 健康检查状态页面
server {
listen 8081;
location /status {
check_status;
access_log off;
}
}使用自定义健康检查端点
# 手动实现简单健康检查
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
server {
listen 80;
# Nginx 自身健康检查
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 后端代理
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_502 http_503 http_504;
}
}SSL 终止
HTTPS 配置
# /etc/nginx/conf.d/ssl-proxy.conf
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS 主配置
server {
listen 443 ssl http2;
server_name api.example.com;
# SSL 证书
ssl_certificate /etc/ssl/certs/api.example.com.crt;
ssl_certificate_key /etc/ssl/private/api.example.com.key;
# SSL 协议与加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 安全响应头
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
# 反向代理到后端
location / {
proxy_pass http://backend;
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 https;
}
}SSL 证书配置参数
# SSL 安全配置参数说明
| 参数 | 推荐值 | 说明 |
|---|---|---|
| ssl_protocols | TLSv1.2 TLSv1.3 | 禁用不安全的 SSL/TLS 版本 |
| ssl_ciphers | ECDHE-* | 优先使用 ECDHE 密钥交换 |
| ssl_prefer_server_ciphers | off | TLS 1.3 下建议关闭 |
| ssl_session_cache | shared:SSL:10m | 共享会话缓存减少握手 |
| ssl_session_timeout | 1d | 会话缓存有效期 |
| ssl_session_tickets | off | 禁用 Session Tickets(前向保密) |
| ssl_stapling | on | 启用 OCSP Stapling |反向代理高级配置
完整的反向代理配置
upstream api_backend {
least_conn;
server 192.168.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.20:8080 backup;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/api.example.com.crt;
ssl_certificate_key /etc/ssl/private/api.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
# 请求体大小限制
client_max_body_size 50m;
# API 代理
location /api/ {
proxy_pass http://api_backend/;
# 请求头转发
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_send_timeout 30s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
# 重试策略
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
# 长连接支持
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# WebSocket 代理
location /ws/ {
proxy_pass http://api_backend/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# 静态文件缓存
location /static/ {
proxy_pass http://api_backend/static/;
proxy_cache_valid 200 7d;
expires 7d;
add_header Cache-Control "public, immutable";
}
# 健康检查
location /health {
proxy_pass http://api_backend/health;
access_log off;
}
}路径路由与流量分配
# /etc/nginx/conf.d/routing.conf
# 前后端分离路由
upstream frontend {
server 192.168.1.30:80;
}
upstream api_v1 {
server 192.168.1.10:8080;
}
upstream api_v2 {
server 192.168.1.11:8080;
}
upstream websocket {
server 192.168.1.40:8080;
}
server {
listen 80;
server_name app.example.com;
# 前端静态文件
location / {
proxy_pass http://frontend;
}
# API v1
location /api/v1/ {
proxy_pass http://api_v1/;
}
# API v2(金丝雀发布:10% 流量到 v2)
location /api/v2/ {
# split_clients "${remote_addr}" $api_version {
# 10% api_v2;
# * api_v1;
# }
proxy_pass http://api_v2/;
}
# WebSocket
location /ws/ {
proxy_pass http://websocket/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}优点
缺点
总结
Nginx 负载均衡是构建高可用 Web 架构的基础组件。通过合理选择负载均衡算法(轮询、加权、IP Hash、最少连接),配置健康检查自动剔除故障节点,使用 SSL 终止集中管理证书,以及利用反向代理实现路径路由和流量分配,能够构建出稳定可靠的流量分发体系。建议根据后端服务器性能选择合适的权重和算法,开启 keepalive 长连接减少连接开销,并通过 proxy_next_upstream 配置优雅的故障转移策略。
关键知识点
- DevOps 主题的核心是让交付更快、更稳、更可审计。
- 自动化不是把命令脚本化,而是把失败、回滚、权限和观测一起设计进去。
- 生产链路必须明确制品、环境、凭据、配置和责任边界。
项目落地视角
- 把流水线拆成构建、测试、制品、部署、验证和回滚几个阶段。
- 为关键步骤补齐日志、指标、通知和人工兜底点。
- 定期演练扩容、回滚、故障注入和灾备切换。
常见误区
- 只关注部署成功,不关注失败恢复和审计追踪。
- 把环境差异藏在临时脚本或人工操作里。
- 上线频率高了以后,没有标准化制品和配置管理。
进阶路线
- 继续补齐 GitOps、可观测性、平台工程和成本治理。
- 把主题和应用架构、安全、权限、备份恢复联动起来理解。
- 形成团队级平台能力,而不是每个项目重复造轮子。
适用场景
- 当你准备把《Nginx 负载均衡》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合构建自动化交付、基础设施治理、监控告警和生产发布体系。
- 当团队规模扩大、发布频率提升或环境变多时,这类主题会显著影响交付效率。
落地建议
- 所有自动化流程尽量做到幂等、可审计、可回滚。
- 把制品、变量、凭据和执行权限分层管理。
- 定期演练扩容、回滚、密钥轮换和灾备恢复。
排错清单
- 先定位失败发生在代码、构建、制品、环境还是权限层。
- 检查流水线变量、凭据、镜像标签和目标环境配置是否一致。
- 如果问题偶发,重点看并发发布、资源争抢和外部依赖抖动。
复盘问题
- 如果把《Nginx 负载均衡》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《Nginx 负载均衡》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《Nginx 负载均衡》最大的收益和代价分别是什么?
动态 Upstream 与服务发现
在微服务和容器化环境中,后端服务器地址经常变化。Nginx 需要动态感知后端变化。
# 方案1:使用 nginx-upsync-module(开源第三方模块)
# 从 Consul/etcd 动态获取后端服务器列表
# upstream 动态配置(需要编译时添加模块)
upstream dynamic_backend {
# 从 Consul 同步服务器列表
upsync 127.0.0.1:8500/v1/catalog/service/backend upsync_timeout=6m upsync_interval=500ms;
# 备用静态配置
upsync_dump_path /etc/nginx/conf.d/backend_servers.conf;
# 长连接配置
keepalive 32;
}
# 方案2:使用 OpenResty + Lua 实现动态 upstream
# lua_shared_dict backends 1m;
#
# init_worker_by_lua_block {
# local http = require "resty.http"
# local function update_backends()
# local res = http.new():request_uri("http://consul:8500/v1/catalog/service/backend")
# if res and res.status == 200 then
# local servers = require("cjson").decode(res.body)
# local dict = ngx.shared.backends
# for i, s in ipairs(servers) do
# dict:set(s.ServiceID, s.ServiceAddress .. ":" .. s.ServicePort)
# end
# end
# ngx.timer.at(5, update_backends)
# end
# ngx.timer.at(0, update_backends)
# }负载均衡排错实战
# 常见问题排查流程
# 1. 检查 Nginx 配置语法
nginx -t
# 2. 查看错误日志
tail -f /var/log/nginx/error.log
# 3. 测试后端服务是否可达
curl -I http://192.168.1.10:8080/health
curl -v http://192.168.1.10:8080/health 2>&1 | head -20
# 4. 查看当前连接状态
ss -tnp | grep :80 | wc -l
# 5. 检查 upstream 响应时间
# 在日志格式中添加 $upstream_response_time
# 查看慢请求:
awk '$NF > 5 {print $0}' /var/log/nginx/access.log
# 常见错误码排查
# 502 Bad Gateway: 后端服务未启动或崩溃
# 504 Gateway Timeout: 后端处理超时
# 499 Client Closed: 客户端提前断开(通常是前端超时)
# 503 Service Unavailable: 后端全部不可用或被限流
# 502 排查步骤:
# 1. 确认后端服务是否运行:systemctl status backend
# 2. 检查端口是否监听:ss -tlnp | grep 8080
# 3. 检查防火墙:iptables -L -n | grep 8080
# 4. 检查 SELinux:getenforce
# 5. 检查 Nginx 到后端的网络:curl http://backend:8080/health负载均衡性能优化清单
性能优化检查清单:
1. 开启 keepalive 长连接
upstream 中添加 keepalive 32;
proxy_http_version 1.1;
proxy_set_header Connection "";
2. 合理设置连接超时
proxy_connect_timeout 5s; # 连接超时不宜过长
proxy_read_timeout 30s; # 根据后端处理时间调整
proxy_send_timeout 30s;
3. 缓冲区调优
proxy_buffering on;
proxy_buffer_size 8k; # 响应头缓冲
proxy_buffers 8 32k; # 响应体缓冲
4. 选择合适的负载均衡算法
后端性能一致: 轮询
后端性能不均: 加权轮询
请求耗时不均: 最少连接
需要会话保持: IP Hash 或 Cookie
5. 开启 proxy_next_upstream 故障转移
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 2;
6. 监控后端健康状态
设置 max_fails 和 fail_timeout
使用主动健康检查(如果可用)
7. 合理使用备份服务器
backup 服务器只在所有主服务器不可用时启用
适合容灾场景Nginx 负载均衡架构图
+-----------------+
| Client Pool |
+--------+--------+
|
+--------v--------+
| DNS / CDN |
+--------+--------+
|
+--------v--------+
| Nginx LB |
| (SSL 终止) |
+--------+--------+
|
+--------------+--------------+
| | |
+------v------+ +-----v------+ +-----v------+
| Backend-01 | | Backend-02 | | Backend-03 |
| weight=5 | | weight=5 | | weight=3 |
+-------------+ +------------+ +-----+------+
|
+------v------+
| Backup-01 |
| (backup) |
+-------------+
流量路径:
Client → DNS → Nginx (SSL 终止 + 负载均衡) → Backend Pool → Backup (兜底)
监控维度:
- 请求量 (QPS/TPS)
- 响应时间 (P50/P95/P99)
- 错误率 (5xx/4xx)
- 后端健康状态
- 连接数 (活跃/空闲)