一、开篇唠唠嗑

今天咱们来聊聊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 局限性分析

  • 权重计算不考虑实时负载
  • 长连接场景下效果打折
  • 需要配合监控系统使用