Nginx负载均衡简单实验
目录
实验环境
docker版本 Nginx1.18.0。
1台nginx容器。里面开4个端口:
5001-5003 当作节点。80 作为入口。
规划
端口 | 响应 |
---|---|
5001 | 🟢 状态码 200 📄 纯文本 “5001” |
5002 | 🟢 状态码 200 📄 纯文本 “5002” |
5003 | 🟢 状态码 200 📄 纯文本 “5003” |
80 | 根据负载规则转发流量 |
具体配置
端口 5001-5003 server 块
server {
# 监听端口 5001
listen *:5001;
location / {
# 增加头部 Content-Type
add_header 'Content-Type' 'text/plain';
# 返回 200,内容 5001
return 200 '5001';
}
}
# 类推,这是 5002 端口。
server {
listen *:5002;
location / {
add_header 'Content-Type' 'text/plain';
return 200 '5002';
}
}
# 类推 5003 端口
# ...
端口 80 入口 server 块
# 定义服务器群,叫 cluster
# 后续主要修改 upstream 块
upstream cluster {
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003;
}
# 入口服务器配置
server {
listen *:80;
server_name default_server;
location / {
# 代理到服务器群 cluster。
proxy_pass http://cluster;
}
}
ℹ️ 这些块可以写到同一个配置文件里面
负载均衡策略
原生 Nginx 自带下面3种负载均衡策略。
round-robin (循环)
在 5001-5003之间 循环转发。每个服务器都能有机会处理请求。
不指定算法则默认为 round-robin
。
upstream cluster {
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003;
}
启动容器后,请求500次。
结果
Total: 500
5001 Hits: 166
5002 Hits: 167
5003 Hits: 167
least-connected (连接最少优先)
upstream cluster {
least_conn;
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003;
}
启动容器后,请求500次。
结果
Total: 500
5001 Hits: 167
5002 Hits: 167
5003 Hits: 166
和 Round-Robin 没有太大区别,但是在过程中可以看到 Hits 少的节点会被优先请求,直到它跟另2个节点响应了差不多数量的请求。
ip_hash (基于客户端ip)
集群里面的服务器按照ip组建hash环。入口按照客户端请求的IP做hash计算求得结果,然后找到离这个结果最近的hash的服务器。
upstream cluster {
ip_hash;
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003;
}
启动容器后,请求500次。
结果
Total: 500
5001 Hits: 0
5002 Hits: 500
5003 Hits: 0
因为每次以同样的IP发起请求,所以基于IP的hash计算结果不变,每次都转发到同样的节点。
weight (按权重配置)
可以手动配置每个节点的权重。Nginx优先转发到权重较大的节点。
upstream cluster {
server 127.0.0.1:5001 weight=8;
server 127.0.0.1:5002 weight=16;
server 127.0.0.1:5003 weight=24;
}
启动容器后,请求500次。
结果
Total: 500
5001 Hits: 83
5002 Hits: 167
5003 Hits: 250
到这里看到,Nginx近似按照比例转发了。
节点健康检查
max_fails
nginx发现有一个节点响应超时的时候,这一次请求会转发至其他可用节点。然后下次会继续尝试,如果在一段时间内(默认10秒内)几次尝试都超时,则下一个10秒不会再转发到这个节点。
不写 max_fails
时,默认为 1.
如果 max_fails
为 0,则禁用这个节点的检查。
upstream cluster {
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003 max_fails=3;
}
fail_timeout
可以指定nginx在尝试一个节点的时候,指定一段时间,如果这段时间内这个节点失败次数超过 max_fails 则后一段相同的时间都不再转发到这个节点,直到过完这个时间,重新尝试转发。
例 下面的配置描述了:当5003节点在5秒内失败了2次,则下一个5秒不再转发到5003,直到下一个5秒过完后,重新尝试5003。
upstream @serve_cluster {
server 127.0.0.1:5001;
server 127.0.0.1:5002;
server 127.0.0.1:5003 max_fails=2 fail_timeout=5s;
}
附:检测负载均衡效果的方法
在宿主机做一个脚本,用curl给入口发请求。
如果得到5001表示来自5001端口,
如果得到5002表示来自5002端口,以此类推。
将收到的有效内容给对应端口的变量+1.
# 变量
HIT5001=0
HIT5002=0
HIT5003=0
# 按照 on_record <响应内容> 计数
function on_record {
if [[ $1 == '5001' ]]; then
# 获得 '5001',5001 计数
HIT5001=$((HIT5001+1));
elif [[ $1 == '5002' ]]; then
# 获得 '5002',5002 计数
HIT5002=$((HIT5002+1));
elif [[ $1 == '5003' ]]; then
# 获得 '5003',5003 计数
HIT5003=$((HIT5003+1));
else
echo '这个内容不是5001-5003之间的值,它是:' $1
fi
clear
echo 'Total(总请求数量):' $((HIT5001+HIT5002+HIT5003))
echo '5001 Hits(响应次数):' $HIT5001
echo '5002 Hits(响应次数):' $HIT5002
echo '5003 Hits(响应次数):' $HIT5003
}
while true; do
# 隐藏CURL请求过程的进度显示。让它只显示结果。
output=$(curl http://localhost:80 2>/dev/null)
# 拿到响应,让计数器处理。
on_record $output
done;