2. 负载均衡算法基础:轮询、加权轮询、最小连接
聊负载均衡,绕不开的就是算法。说白了,算法决定了流量怎么分、分给谁。我这些年调过的交换机、做过的项目,踩坑最多的往往不是硬件性能,而是算法选型没想清楚。今天咱们就把三个最基础的算法掰开揉碎了讲清楚。
2.1 轮询(Round Robin)
轮询是最简单的算法。它的逻辑就是:挨个来,一个接一个,循环往复。你想想看,就像食堂打饭,窗口1、窗口2、窗口3,轮流叫号,谁也不多打一份。
在交换架构里,轮询的实现非常轻量。每个后端节点维护一个计数器,来一个请求就加1,然后取模。代码写出来就几行:
# 伪代码示例:轮询调度
servers = ["S1", "S2", "S3"]
index = 0
def get_server():
global index
server = servers[index % len(servers)]
index += 1
return server
轮询的优点很明显:实现简单、无状态、CPU开销极低。但缺点也致命——它假设所有节点性能一样。我在项目中遇到过,三台服务器配置不同,一台是64核,两台是16核,轮询下去,64核那台闲得发慌,16核的却快被压垮了。嗯,这就是轮询的局限性。
2.2 加权轮询(Weighted Round Robin)
加权轮询,说白了就是给轮询加了个权重。你能力强,就多分点活;能力弱,就少分点。这个逻辑很符合直觉,对吧?
我习惯把权重理解为“配额”。比如三台服务器,权重分别是5、3、2,那每10个请求里,S1处理5个,S2处理3个,S3处理2个。实现上,常见的做法是“平滑加权轮询”,它能避免短时间内的请求集中打到同一台机器上。
# 伪代码示例:平滑加权轮询
servers = [
{"name": "S1", "weight": 5, "current": 0},
{"name": "S2", "weight": 3, "current": 0},
{"name": "S3", "weight": 2, "current": 0}
]
total_weight = 10
def get_server():
# 每个节点增加自己的权重
for s in servers:
s["current"] += s["weight"]
# 选current最大的
best = max(servers, key=lambda s: s["current"])
# 减去总权重
best["current"] -= total_weight
return best["name"]
加权轮询比普通轮询灵活多了。我记得有一次做CDN边缘节点的负载均衡,后端机器有不同代际的硬件,老机器权重设1,新机器设3,效果立竿见影。不过要注意,权重不是越大越好,得结合实际压测数据来调。
2.3 最小连接(Least Connections)
最小连接算法,看名字就知道——谁当前处理的连接数最少,就把新请求发给谁。这个算法很聪明,它不依赖预设的权重,而是动态感知后端负载。
你想想看,如果某个请求处理特别慢,那它占着连接的时间就长,连接数自然就高。最小连接算法会自动避开这个“慢节点”,把新请求发给更空闲的机器。这比加权轮询更智能,因为它能应对请求处理时间不一致的情况。
# 伪代码示例:最小连接调度
servers = [
{"name": "S1", "connections": 12},
{"name": "S2", "connections": 8},
{"name": "S3", "connections": 15}
]
def get_server():
# 选连接数最少的
best = min(servers, key=lambda s: s["connections"])
best["connections"] += 1
return best["name"]
def release_server(server_name):
# 请求完成后释放连接
for s in servers:
if s["name"] == server_name:
s["connections"] -= 1
break
最小连接算法在长连接场景下特别好用。比如数据库连接池、WebSocket服务。我曾经在一个即时通讯项目里用最小连接做网关负载均衡,效果比轮询好了不止一个量级。但要注意,短连接场景下,连接数频繁波动,反而可能导致调度抖动。
2.4 三种算法对比
我把这三个算法放在一起对比一下,方便你选型时参考:
| 算法 | 核心逻辑 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|---|
| 轮询 | 循环分配 | 实现简单、无状态 | 不考虑节点差异 | 同配置、短连接 |
| 加权轮询 | 按权重分配 | 支持异构节点 | 权重需手动调优 | 异构集群、静态负载 |
| 最小连接 | 选连接最少 | 动态感知负载 | 短连接场景抖动 | 长连接、处理时间不均 |
2.5 核心逻辑流程图
下面这张图,我把三种算法的决策逻辑画出来了。你看一眼就能明白它们之间的区别:
这张图把三种算法的决策路径画得很清楚。从新请求到达开始,根据你选择的算法,走不同的分支,最终落到后端节点上。我个人建议,刚开始做负载均衡设计时,先把这三种算法吃透,再考虑更复杂的算法。
好了,这一章的内容就到这里。三种算法各有千秋,没有银弹。关键是根据你的业务场景,选最合适的那个。