Nginx 作为高性能的负载均衡器,提供了多种调度算法来分发客户端请求。以下从原理、配置到实战案例,详细解析 Nginx 的调度算法。
一、Nginx 负载均衡基本原理
Nginx 通过 upstream
模块定义后端服务器组,并使用调度算法将请求分发给组内服务器。基本配置结构:
http {
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com weight=3;
server backend3.example.com down; # 标记为不可用
}
server {
location / {
proxy_pass http://backend;
}
}
}
二、常用调度算法详解
1. 轮询(Round Robin)
原理:按顺序依次将请求分发给后端服务器,默认算法。
配置:无需显式指定。
特点:
- 简单公平,适用于服务器性能相近的场景。
- 不考虑服务器负载差异,可能导致性能不均。
示例:
upstream backend {
server backend1.example.com;
server backend2.example.com;
}
2. 加权轮询(Weighted Round Robin)
原理:根据服务器性能分配权重(weight
),权重越高分得请求越多。
配置:通过 weight
参数设置权重(默认 1)。
适用场景:后端服务器硬件性能差异较大时。
示例:
upstream backend {
server backend1.example.com weight=5; # 处理 5/8 的请求
server backend2.example.com weight=3; # 处理 3/8 的请求
}
3. IP 哈希(IP Hash)
原理:根据客户端 IP 的哈希值确定服务器,确保同一客户端始终访问同一服务器。
配置:使用 ip_hash
指令。
适用场景:需 session 会话保持的场景(如购物车、登录状态)。
示例:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
注意:
- 服务器增减会导致哈希值重新分布,可能丢失会话。
- 仅基于客户端 IP 的前三个段计算哈希(IPv4)。
4. 最少连接(Least Connections)
原理:将请求分发给当前连接数最少的服务器。
配置:使用 least_conn
指令。
适用场景:长连接场景(如数据库连接、WebSocket)。
示例:
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
5. 加权最少连接(Weighted Least Connections)
原理:结合权重与连接数,优先选择 “当前连接数 / 权重” 比值最小的服务器。
配置:least_conn
+ weight
。
示例:
upstream backend {
least_conn;
server backend1.example.com weight=5;
server backend2.example.com weight=3;
}
6. 通用哈希(Generic Hash)
原理:根据用户指定的 key(如 URL、参数)计算哈希值,确定服务器。
配置:使用 hash key [consistent]
指令。
适用场景:需自定义分发规则的场景(如按用户 ID 路由)。
示例:按 URL 路径分发:
upstream backend {
hash $request_uri;
server backend1.example.com;
server backend2.example.com;
}
一致性哈希(Consistent Hash):
- 当服务器增减时,仅影响少量请求的路由。
- 配置:
hash $request_uri consistent;
。
三、高级调度参数
1. 健康检查(Health Check)
通过 server
指令的参数控制服务器状态:
down
:标记服务器永久不可用。backup
:作为备份服务器,仅当其他服务器均不可用时启用。max_fails
和fail_timeout
:连续失败次数达到阈值后,暂停转发请求。
示例:
upstream backend {
server backend1.example.com max_fails=3 fail_timeout=30s; # 连续3次失败后,暂停30秒
server backend2.example.com backup; # 备份服务器
}
2. 响应时间感知(Fair)
需配合第三方模块 ngx_http_upstream_fair
,根据服务器响应时间动态调整分发权重。
配置:
upstream backend {
fair; # 需要安装 fair 模块
server backend1.example.com;
server backend2.example.com;
}
四、实战案例
案例 1:Web 服务负载均衡
需求:将 HTTP 请求分发给两台性能不同的 Web 服务器。
配置:
upstream web_backend {
server web1.example.com weight=3; # 性能较强的服务器
server web2.example.com weight=1; # 性能较弱的服务器
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://web_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
案例 2:会话保持(Shopping Cart)
需求:确保用户购物车数据始终由同一服务器处理。
配置:
upstream cart_backend {
ip_hash; # 基于客户端 IP 实现会话保持
server cart1.example.com;
server cart2.example.com;
}
server {
location /cart/ {
proxy_pass http://cart_backend;
}
}
案例 3:长连接服务(WebSocket)
需求:对实时聊天服务进行负载均衡。
配置:
upstream chat_backend {
least_conn; # 适合长连接场景
server chat1.example.com;
server chat2.example.com;
}
server {
listen 443 ssl;
location /ws/ {
proxy_pass http://chat_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
五、调度算法选择建议
场景 | 推荐算法 | 理由 |
---|---|---|
无状态服务 | 加权轮询 | 简单高效,按服务器性能分配请求 |
会话保持 | IP 哈希或通用哈希 | 确保同一客户端始终访问同一服务器 |
长连接服务(数据库 / Ws) | 最少连接 | 避免服务器连接数过载 |
动态内容分发 | 响应时间感知(Fair) | 根据服务器负载和响应速度动态调整 |
缓存服务 | 一致性哈希 | 减少服务器增减时的缓存失效比例 |
六、性能优化建议
-
启用 keepalive:减少连接建立开销。
upstream backend { server backend1.example.com; keepalive 32; # 每个 worker 保持 32 个空闲连接 }
-
调整 worker 进程数:与 CPU 核心数匹配。
worker_processes auto; # 自动检测 CPU 核心数
-
监控与告警:通过 Nginx Plus 或第三方工具监控后端服务器健康状态。
七、常见问题与解决方案
- IP 哈希导致负载不均:部分客户端 IP 分布不均时,改用通用哈希(如基于用户 ID)。
- 会话丢失:使用分布式会话存储(如 Redis)替代服务器本地会话。
- 后端服务器故障:结合健康检查与自动故障转移机制(如
max_fails
)。
通过合理选择调度算法和优化配置,Nginx 可有效提升系统吞吐量和可用性。