1. 为什么需要负载均衡?

想象一下,你开了一家网红奶茶店,突然涌进来1000个顾客。如果只有一个服务员,肯定要排队到天荒地老。这时候你决定多雇几个员工,但如何合理分配顾客到不同窗口呢?这就是负载均衡要解决的问题——把流量合理地分配到多个服务器上,避免单点过载。

在OpenResty(基于Nginx的Web平台)中,我们通过upstream模块就能实现各种负载均衡策略。今天我们就重点聊聊最常用的两种算法:轮询(Round Robin)IP哈希(IP Hash)


2. 环境搭建速成课

先来准备实验环境:

sudo apt-get install -y openssl libpcre3 libpcre3-dev zlib1g zlib1g-dev
wget https://openresty.org/download/openresty-1.21.4.1.tar.gz
tar -zxvf openresty-1.21.4.1.tar.gz
cd openresty-1.21.4.1/
./configure
make
sudo make install

3. 轮询算法:公平分蛋糕

3.1 基础配置
http {
    upstream backend {
        # 轮询模式(默认策略)
        server 192.168.1.101:8080;  # 服务器A
        server 192.168.1.102:8080;  # 服务器B
        server 192.168.1.103:8080;  # 服务器C
    }

    server {
        listen 80;
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
        }
    }
}

这个配置会让请求像发扑克牌一样依次分发给三台服务器:1号请求给A,2号给B,3号给C,4号又回到A...

3.2 进阶玩法:加权轮询
upstream backend {
    server 192.168.1.101 weight=3;  # 性能最好的服务器分配3倍流量
    server 192.168.1.102 weight=2;  # 中等配置分配2倍
    server 192.168.1.103;           # 默认weight=1
}

现在流量分配比例变成3:2:1,就像给不同能力的员工分配不同数量的顾客。


4. IP哈希算法:让老客户找熟人

4.1 基础实现
upstream backend {
    ip_hash;  # 开启IP哈希模式
    
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
    server 192.168.1.103:8080 down;  # 标记故障节点
}

这个算法会根据客户端IP计算哈希值,固定分配到某台服务器。就像银行VIP客户每次都找同一个经理办理业务。

4.2 自定义哈希因子
upstream backend {
    hash $remote_addr$http_user_agent consistent;  # 组合IP+浏览器类型
    
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
}

通过组合多个变量,可以更精细地控制分发逻辑,比如让同一用户用同款浏览器时固定访问某服务器。


5. 技术选型指南针

5.1 轮询适用场景
  • 无状态服务(如静态资源服务器)
  • 服务器配置完全相同的集群
  • 需要快速实现基础负载的场景
5.2 IP哈希适用场景
  • 需要会话保持的应用(如购物车功能)
  • 服务器本地缓存利用率要求高
  • 客户端IP分布均匀的环境

6. 避坑指南:那些年我踩过的雷

  1. 健康检查不能少
    加上nginx_upstream_check_module模块:

    upstream backend {
        server 192.168.1.101:8080;
        check interval=3000 rise=2 fall=3 timeout=1000;
    }
    
  2. 权重分配不是银弹
    突然给某台服务器加大权重,可能导致瞬时过载。建议采用渐进式调整策略。

  3. 动态节点管理
    使用Consul等工具实现服务发现:

    location /upstreams {
        content_by_lua_block {
            local consul = require "resty.consul"
            local c = consul:new()
            local nodes = c:get_healthy_services("backend-service")
            ngx.say("当前可用节点:", table.concat(nodes, ", "))
        }
    }
    

7. 性能优化小妙招

  • 开启keepalive长连接:
    upstream backend {
        server 192.168.1.101;
        keepalive 32;  # 保持32个长连接
    }
    
  • 使用共享内存做状态存储:
    lua_shared_dict load_balancer 10m;
    

8. 总结与展望

轮询就像食堂打饭窗口,保证每个人都能快速轮到;IP哈希则像银行VIP室,让特定客户享受专属服务。实际生产中,我们常会看到这两种策略的组合使用,比如先用IP哈希做粗粒度分流,再用轮询做细粒度分配。

随着云原生技术的发展,基于Kubernetes的智能负载均衡方案越来越普及。但万变不离其宗,理解这些基础算法,仍然是构建高可用系统的必修课。