负载均衡
负载均衡是将网络请求分发到多个服务器的技术。本章将介绍如何使用 Nginx 实现负载均衡。
负载均衡概述
什么是负载均衡?
负载均衡(Load Balancing)是一种将工作负载分布到多个服务器上的技术,目的是:
- 提高性能:并行处理更多请求
- 提高可用性:一台服务器故障,其他服务器继续服务
- 提高扩展性:可以动态添加服务器
Nginx 负载均衡的优势
- 配置简单:几行配置即可实现
- 性能优异:高并发处理能力
- 多种策略:支持多种负载均衡算法
- 健康检查:自动检测后端服务器状态
- 会话保持:支持基于 Cookie 的会话粘滞
upstream 模块
基本配置
# 定义后端服务器组
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
}
}
解释:
upstream定义后端服务器组server指定每台后端服务器的地址和端口proxy_pass引用 upstream 组
负载均衡策略
1. 轮询(Round Robin)
默认策略,按顺序分发请求:
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
工作流程:
请求1 → 服务器1
请求2 → 服务器2
请求3 → 服务器3
请求4 → 服务器1
...
2. 加权轮询(Weighted Round Robin)
根据权重分发请求,权重越高,分到的请求越多:
upstream backend {
server 192.168.1.101:8080 weight=5; # 处理 5/8 的请求
server 192.168.1.102:8080 weight=2; # 处理 2/8 的请求
server 192.168.1.103:8080 weight=1; # 处理 1/8 的请求
}
解释:
- 适用于服务器性能不同的情况
- 高配置服务器设置较高权重
3. IP Hash
根据客户端 IP 地址的哈希值分配服务器,保证同一客户端总是访问同一服务器:
upstream backend {
ip_hash;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
解释:
- 适合需要会话保持的应用
- 同一 IP 的请求总是发送到同一后端
- 如果后端服务器变化,可能会重新分配
4. 最少连接(Least Connections)
将请求发送到当前连接数最少的服务器:
upstream backend {
least_conn;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
解释:
- 适合请求处理时间差异较大的场景
- 自动将请求发送到最空闲的服务器
5. 一致性哈希(需要第三方模块)
根据请求的某个特征进行哈希:
# 需要安装 ngx_http_upstream_hash_module
upstream backend {
hash $request_uri consistent;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
策略对比
| 策略 | 适用场景 | 特点 |
|---|---|---|
| 轮询 | 服务器性能相同 | 简单公平 |
| 加权轮询 | 服务器性能不同 | 按能力分配 |
| IP Hash | 需要会话保持 | 客户端绑定 |
| 最少连接 | 请求时间差异大 | 动态负载 |
服务器参数
weight(权重)
upstream backend {
server 192.168.1.101:8080 weight=3;
server 192.168.1.102:8080 weight=1;
}
max_fails 和 fail_timeout
upstream backend {
# max_fails: 最大失败次数
# fail_timeout: 失败后的超时时间
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
}
解释:
- 在
fail_timeout时间内失败max_fails次,则标记为不可用 fail_timeout后,再次尝试连接
backup(备用服务器)
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080 backup; # 备用服务器
}
解释:
backup服务器只在其他服务器都不可用时使用- 适合用于故障转移
down(标记下线)
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080 down; # 永久下线
server 192.168.1.103:8080;
}
健康检查
被动健康检查
Nginx 通过响应判断后端健康状态:
upstream backend {
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
}
主动健康检查(商业版)
Nginx Plus 支持主动健康检查:
upstream backend {
zone backend 64k;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
# 主动健康检查
health_check interval=5s fails=3 passes=2 uri=/health match=status_ok;
}
match status_ok {
status 200;
header Content-Type ~ "application/json";
body ~ '"status":"ok"';
}
开源版主动健康检查
可以使用第三方模块实现:
# 安装 nginx_upstream_check_module
# https://github.com/yaoweibin/nginx_upstream_check_module
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "HEAD /health HTTP/1.1\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
会话保持
基于 IP 的会话保持
使用 ip_hash 策略:
upstream backend {
ip_hash;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}
基于 Cookie 的会话保持
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
# 使用 sticky cookie(需要 nginx-sticky-module)
# sticky cookie srv_id expires=1h;
}
# 或通过应用层实现
server {
location / {
proxy_pass http://backend;
proxy_set_header X-Session-ID $cookie_sessionid;
}
}
基于学习模式(Nginx Plus)
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
sticky learn
create=$upstream_cookie_sessionid
lookup=$cookie_sessionid
zone=client_sessions:1m;
}
高级配置
限制连接数
upstream backend {
server 192.168.1.101:8080 max_conns=100; # 最大连接数
server 192.168.1.102:8080 max_conns=100;
}
慢启动
upstream backend {
server 192.168.1.101:8080 slow_start=30s; # 30秒内逐渐增加流量
server 192.168.1.102:8080;
}
队列配置
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
# 所有服务器繁忙时,排队等待
queue 100 timeout=60s;
}
实际场景配置
场景 1:Web 应用负载均衡
upstream web_cluster {
least_conn;
server 192.168.1.101:8080 weight=3;
server 192.168.1.102:8080 weight=3;
server 192.168.1.103:8080 weight=1;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://web_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
场景 2:API 服务器负载均衡
upstream api_cluster {
ip_hash; # 保持会话
server 192.168.1.101:3000 max_fails=3 fail_timeout=30s;
server 192.168.1.102:3000 max_fails=3 fail_timeout=30s;
server 192.168.1.103:3000 backup;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://api_cluster;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_next_upstream error timeout http_503;
}
}
场景 3:数据库读负载均衡
upstream mysql_read {
least_conn;
server 192.168.1.101:3306 weight=5;
server 192.168.1.102:3306 weight=3;
server 192.168.1.103:3306 weight=1;
}
# 注意:Nginx 不直接代理 MySQL
# 这里仅作示例,实际使用需要专门的数据库代理
场景 4:灰度发布
upstream stable {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
}
upstream canary {
server 192.168.1.103:8080;
}
server {
listen 80;
server_name example.com;
# 根据 Cookie 分流
set $backend "stable";
if ($cookie_canary = "true") {
set $backend "canary";
}
# 根据 Header 分流
if ($http_x_canary = "true") {
set $backend "canary";
}
# 按比例分流(10% 流量到新版本)
split_clients "${remote_addr}" $variant {
10% canary;
* stable;
}
location / {
proxy_pass http://$variant;
proxy_set_header Host $host;
}
}
监控和调试
状态页面
server {
listen 80;
server_name localhost;
location /upstream_status {
stub_status on;
allow 127.0.0.1;
deny all;
}
}
日志配置
log_format upstream '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'upstream=$upstream_addr '
'response_time=$upstream_response_time '
'status=$upstream_status';
server {
access_log /var/log/nginx/upstream.log upstream;
}
添加调试头
server {
add_header X-Upstream-Addr $upstream_addr;
add_header X-Upstream-Status $upstream_status;
add_header X-Upstream-Response-Time $upstream_response_time;
location / {
proxy_pass http://backend;
}
}
小结
本章我们学习了:
- 负载均衡的概念和优势
- upstream 模块的配置
- 多种负载均衡策略(轮询、加权、IP Hash、最少连接)
- 服务器参数配置(weight、max_fails、backup)
- 健康检查机制
- 会话保持方法
- 实际场景配置示例
- 监控和调试
练习
- 配置一个基本的轮询负载均衡
- 配置加权负载均衡
- 配置 IP Hash 会话保持
- 实现灰度发布配置