1. 负载均衡基础认知
第一次接触Nginx的负载均衡功能是在2013年一个电商促销项目中。当时我们的单台服务器在流量高峰时CPU直接飙到100%,页面响应时间超过5秒。临时加机器后发现流量分配不均,有的服务器闲置有的过载。这时Nginx的负载均衡功能就成了救命稻草。
负载均衡本质上是一种流量分配策略,就像餐厅的多条取餐通道。当大量顾客(请求)同时到达时,领班(Nginx)会根据各窗口(服务器)的忙碌程度,智能分配顾客到不同的队列中。这种分配不是简单的轮流值班,而是需要考虑服务器性能、当前负载、响应速度等多重因素。
Nginx作为负载均衡器有几个突出优势:首先是性能强悍,单机就能轻松处理数万并发;其次是配置灵活,支持多种负载策略;最重要的是它还能做反向代理、静态缓存等,是多面手。我见过不少创业公司直接用Nginx既做Web服务器又当负载均衡,省去了专门采购硬件负载均衡器的成本。
2. 环境准备与基础配置
2.1 服务器集群搭建
假设我们现在要为一个日活10万的应用搭建负载均衡。通常需要:
- 2台Nginx服务器(主备部署)
- 至少3台应用服务器
- 共享存储或数据库服务器
我习惯用Ansible批量初始化服务器环境。以下是一个基础的环境检查脚本:
bash复制#!/bin/bash
# 检查系统资源
echo "CPU核心数: $(nproc)"
echo "内存总量: $(free -h | awk '/Mem/{print $2}')"
echo "磁盘空间: $(df -h / | awk 'NR==2{print $4}')"
# 检查必要软件
for pkg in nginx openssl net-tools; do
which $pkg >/dev/null || echo "$pkg 未安装"
done
2.2 Nginx安装优化
在Ubuntu 20.04上推荐用官方源安装最新稳定版:
bash复制sudo apt install curl gnupg2 ca-certificates lsb-release
echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo apt update
sudo apt install nginx=1.20.*
安装后有几个关键配置需要调整:
nginx复制# /etc/nginx/nginx.conf 主配置
worker_processes auto; # 自动匹配CPU核心数
worker_rlimit_nofile 100000; # 每个worker能打开的文件描述符数
events {
worker_connections 4096; # 单个worker最大连接数
multi_accept on; # 同时接受多个连接
}
重要提示:生产环境一定要配置ulimit,否则会出现"too many open files"错误。建议在/etc/security/limits.conf添加:
code复制* soft nofile 100000 * hard nofile 100000
3. 负载均衡核心配置
3.1 upstream模块详解
Nginx通过upstream模块定义服务器组。这是我常用的一个生产配置模板:
nginx复制upstream backend {
# 基础轮询策略
server 192.168.1.101:8080 weight=5; # 权重配置
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.103:8080 backup; # 备用服务器
# 会话保持配置
sticky cookie srv_id expires=1h domain=.example.com path=/;
# 健康检查
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
关键参数解析:
weight:权重越高分配的请求越多,适合配置不同的服务器性能max_fails:失败次数超过该值则认为服务器不可用fail_timeout:服务器被标记为不可用的超时时间backup:备用服务器,只有当其他服务器都不可用时才会启用
3.2 负载均衡策略对比
Nginx支持多种负载策略,通过一个实际压测案例说明差异:
| 策略类型 | 配置示例 | 适用场景 | QPS测试结果 |
|---|---|---|---|
| 轮询(RR) | 默认配置 |
服务器性能均衡 | 12,500 |
| 加权轮询 | weight=3 |
服务器配置不均 | 14,200 |
| IP哈希 | ip_hash |
需要会话保持 | 11,800 |
| 最少连接 | least_conn |
长连接场景 | 15,300 |
| 响应时间 | fair (需模块) |
动态调整负载 | 13,600 |
实测技巧:用wrk工具进行基准测试:
bash复制wrk -t4 -c1000 -d60s --latency http://loadbalancer
4. 高级功能实现
4.1 健康检查机制
Nginx Plus有官方健康检查,开源版可以通过第三方模块或手动配置:
nginx复制server {
location /nginx_status {
stub_status on;
access_log off;
allow 192.168.1.0/24;
deny all;
}
location /backend_check {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503;
}
}
我开发过一个用Lua脚本增强的健康检查方案:
lua复制location = /health {
content_by_lua_block {
local hc = require "resty.upstream.healthcheck"
local ok, err = hc.spawn_checker{
shm = "healthcheck",
upstream = "backend",
type = "http",
http_req = "GET /ping HTTP/1.0\r\nHost: backend\r\n\r\n",
interval = 2000,
timeout = 1000,
fall = 3,
rise = 2,
valid_statuses = {200, 302}
}
ngx.say(ok and "Healthcheck enabled" or "Error: "..err)
}
}
4.2 动态负载调整
在Kubernetes环境中,可以通过Nginx Ingress实现自动扩缩容:
yaml复制# ingress-nginx-controller ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
data:
upstream-keepalive-connections: "200"
upstream-keepalive-requests: "10000"
upstream-keepalive-timeout: "60s"
load-balance: "ewma" # 指数加权移动平均算法
对于传统环境,我常用Consul+OpenResty实现服务发现:
bash复制# 注册服务到Consul
curl -X PUT -d '{"name":"web","address":"192.168.1.101","port":8080}' \
http://consul:8500/v1/agent/service/register
对应的Nginx配置自动更新:
lua复制location /upstreams {
content_by_lua_block {
local consul = require "resty.consul"
local c = consul:new()
local res, err = c:get("/v1/health/service/web")
ngx.header["Content-Type"] = "text/plain"
for _, service in ipairs(res.body) do
ngx.say(string.format("server %s:%d;",
service.Service.Address,
service.Service.Port))
end
}
}
5. 性能调优实战
5.1 TCP协议栈优化
在/etc/sysctl.conf中添加:
conf复制net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 32768
net.ipv4.tcp_keepalive_time = 600
针对Nginx的TCP优化:
nginx复制http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 10000;
# 缓冲区优化
client_body_buffer_size 16k;
client_header_buffer_size 4k;
client_max_body_size 8m;
large_client_header_buffers 4 8k;
}
5.2 压测与瓶颈分析
使用Jmeter进行阶梯式压测时,发现几个典型问题:
- TIME_WAIT堆积:
bash复制ss -s | grep TIME-WAIT
解决方案是启用tcp_tw_recycle和增加本地端口范围:
conf复制net.ipv4.ip_local_port_range = 1024 65535
- 后端响应慢导致队列堆积:
nginx复制server {
listen 80 backlog=4096; # 增大监听队列
location / {
proxy_connect_timeout 2s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
proxy_buffer_size 16k;
proxy_buffers 4 32k;
}
}
- 内存泄漏排查:
bash复制# 监控Nginx内存使用
watch -n 1 "ps -eo pid,rss,comm | grep nginx"
6. 安全防护配置
6.1 DDoS防护
在Nginx层面实现基础防护:
nginx复制# 限制单个IP连接数
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 50;
# 限制请求速率
limit_req_zone $binary_remote_addr zone=reqlimit:10m rate=50r/s;
limit_req zone=reqlimit burst=100 nodelay;
# 封禁恶意IP
geo $bad_ips {
default 0;
include /etc/nginx/blocked_ips.conf;
}
6.2 SSL安全加固
推荐配置(使用Let's Encrypt证书):
nginx复制server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
# HSTS头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
}
7. 监控与日志分析
7.1 Prometheus监控
配置Nginx暴露metrics:
nginx复制server {
location /metrics {
stub_status on;
access_log off;
# Prometheus格式输出
content_by_lua_block {
local metric = require "ngx.prometheus"
metric.collect()
}
}
}
对应的Prometheus配置:
yaml复制scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx:9113']
metrics_path: /metrics
7.2 日志分析技巧
推荐日志格式:
nginx复制log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'upstream_addr=$upstream_addr '
'request_time=$request_time '
'upstream_response_time=$upstream_response_time';
用GoAccess生成实时报表:
bash复制goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
--real-time-html \
--port=7890 \
--output=/var/www/report.html
8. 常见故障排查
8.1 502 Bad Gateway
排查步骤:
- 检查后端服务是否存活:
bash复制curl -I http://backend:8080/health
- 查看Nginx错误日志:
bash复制tail -f /var/log/nginx/error.log | grep upstream
- 检查防火墙规则:
bash复制iptables -L -n | grep 8080
- 验证DNS解析:
nginx复制resolver 8.8.8.8 valid=30s; # 明确配置DNS服务器
8.2 负载不均衡
诊断方法:
- 查看当前连接分配:
bash复制watch -n 1 "curl -s http://localhost/nginx_status | grep active"
- 检查服务器权重配置:
nginx复制upstream backend {
server 192.168.1.101 weight=3;
server 192.168.1.102 weight=1;
}
- 如果是ip_hash策略,检查客户端IP是否过于集中
9. 架构演进建议
随着业务增长,负载均衡架构通常会经历几个阶段:
- 初级阶段:单Nginx + 多应用服务器
- 中级阶段:Nginx主备 + Keepalived VIP
- 高级阶段:DNS轮询 + 多地域部署 + 全局负载均衡
对于日PV超过千万的系统,建议考虑:
- 使用Nginx Plus获得官方支持
- 引入CDN分担静态资源压力
- 实施灰度发布系统
- 配置自动化扩缩容策略
我在实际项目中总结的经验是:不要过早优化,先从简单的轮询策略开始,通过监控发现瓶颈后再针对性调整。曾经有个客户一开始就配置了复杂的fair模块,结果因为配置不当导致CPU高了20%,后来切回least_conn反而更稳定。