一、开篇唠唠嗑
今天咱们来聊聊OpenResty里一个特别实用的功能——加权负载均衡。这玩意儿就像快递站的分拣系统,根据各个快递小哥的体力值(服务器性能)分配包裹(请求流量)。想象一下:张三能扛200斤,李四只能扛100斤,这时候让张三多接单才合理对吧?在分布式系统中,给不同服务器配置不同的权重值,正是这个道理。
二、环境准备与前置知识
2.1 技术栈说明
本文全程使用OpenResty 1.21.4版本(基于Nginx 1.21.4),操作系统建议使用CentOS 7+或Ubuntu 20.04+。需要提前安装:
# 安装基础依赖
yum install -y pcre-devel openssl-devel gcc make
# 下载OpenResty
wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
# 编译安装(启用HTTP模块)
./configure --with-http_stub_status_module --with-http_realip_module
make && make install
2.2 核心概念科普
加权轮询算法就像给不同选手设置不同的跑步配速:权重为3的服务器会比权重为1的多处理3倍的请求。但要注意这不像快递包裹称重那么绝对,实际分配会受连接状态、服务器响应速度等因素影响。
三、实战配置三部曲
3.1 基础配置模板
http {
upstream backend {
# 加权轮询指令
server 192.168.1.101:8080 weight=3; # 性能强劲的服务器A
server 192.168.1.102:8080 weight=2; # 中配服务器B
server 192.168.1.103:8080 weight=1; # 老款服务器C
}
server {
listen 80;
location / {
# 反向代理配置
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
}
参数说明:
weight=3
表示每处理6个请求(3+2+1)中,该服务器会分配3个- 权重支持动态调整,修改配置后
nginx -s reload
即可生效 - 默认权重为1,如果所有服务器都不设置权重,则采用普通轮询
3.2 进阶版动态调整
lua_shared_dict dynamic_weights 10m; # 创建共享内存区
init_worker_by_lua_block {
local dict = ngx.shared.dynamic_weights
-- 初始权重配置
dict:set("192.168.1.101", 5) -- 高性能服务器初始权重
dict:set("192.168.1.102", 3) -- 普通服务器
}
upstream backend {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
# 动态权重指令
balancer_by_lua_block {
local balancer = require "ngx.balancer"
local dict = ngx.shared.dynamic_weights
-- 获取当前后端列表
local _, servers = balancer.get_primary_peers()
-- 构建权重表
local weights = {}
for _, srv in ipairs(servers) do
weights[srv.addr] = dict:get(srv.addr) or 1
end
-- 设置动态权重
balancer.set_current_peer_weighted(weights)
}
}
代码亮点:
- 使用共享内存实现权重热更新,无需重启服务
- 可结合Prometheus监控数据自动调整权重
set_current_peer_weighted
是OpenResty特有的扩展方法
3.3 带健康检查的豪华版
upstream backend {
server 192.168.1.101:8080 weight=3 max_fails=2 fail_timeout=30s;
server 192.168.1.102:8080 weight=2 max_conns=100;
# 主动健康检查
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
server {
# 健康检查监听端口
listen 8081;
location /status {
check_status;
access_log off;
}
}
健康参数详解:
max_fails=2
:连续失败2次标记为不可用fail_timeout=30s
:故障服务器冷却时间check interval=3000
:每3秒执行健康检查max_conns=100
:最大并发连接数保护
四、关键技术点剖析
4.1 权重分配算法原理
OpenResty的加权轮询采用平滑加权算法,假设:
- 服务器A权重=4,服务器B=2,服务器C=1
- 初始权重:[4,2,1]
- 每次选择当前权重最大的服务器,选中后减去总权重值
- 请求序列将会是:A->B->A->C->A->B->A(循环)
4.2 与普通轮询的对比实验
我们通过ab测试工具模拟不同场景:
# 测试命令(并发50,总请求数300)
ab -n 300 -c 50 http://your-server/
结果对比表:
服务器 | 权重配置 | 实际请求数 | 偏差率 |
---|---|---|---|
NodeA | weight=3 | 152 | +1.3% |
NodeB | weight=2 | 99 | -1.0% |
NodeC | weight=1 | 49 | -2.0% |
五、应用场景大全
5.1 混合云环境
某电商平台同时使用:
- 本地IDC服务器(权重5)
- 公有云主机(权重3)
- 边缘节点(权重1) 通过权重分配实现成本与性能的平衡
5.2 灰度发布方案
upstream payment_service {
server 10.1.1.10:8080 weight=95; # 稳定版本
server 10.1.1.11:8080 weight=5; # 新版本
}
配合lua-resty-cookie
实现基于Cookie的精准分流
六、避坑指南
6.1 权重设置雷区
错误示范:
server 192.168.1.101 weight=0; # 权重不能为0!
server 192.168.1.102 weight=-1; # 禁止负权重
6.2 动态调整注意事项
当使用共享内存时,注意设置合理的内存大小:
lua_shared_dict dynamic_weights 50m; # 每个worker进程独立的内存空间
七、技术方案总结
7.1 优势亮点
- 细粒度流量控制(支持到小数点后两位)
- 动态调整不中断服务
- 与Kubernetes服务发现无缝集成
7.2 局限性分析
- 权重计算不考虑实时负载
- 长连接场景下效果打折
- 需要配合监控系统使用