主题
第 3 章 · 调度算法大全
生活类比:银行大堂经理把客户引到柜台,可以有很多种「规矩」——
按顺序轮流(轮询)、大柜台多接几位(加权)、哪队短去哪(最少连接)、VIP 固定专属经理(粘性哈希)……
没有最好的算法,只有最适合你场景的算法。
3.1 学习目标
- 掌握 8 种常见调度算法的工作原理
- 能用生活例子向非技术人员解释每种算法
- 知道每种算法的适用场景和坑
- 能运行
code/lb_simulator.py观察分发结果
3.2 算法总览
| 算法 | 英文 | 一句话 | 生活类比 |
|---|---|---|---|
| 轮询 | Round Robin | A→B→C→A→B→C | 三个柜台依次叫号 |
| 加权轮询 | Weighted RR | 能力强的多分配 | 32 核机器多接活 |
| 随机 | Random | 随机选一台 | 抽签决定窗口 |
| 最少连接 | Least Connections | 选当前最闲的 | 哪队短排哪 |
| 加权最少连接 | Weighted LC | 能力×空闲度综合 | 大柜台且队短优先 |
| IP 哈希 | IP Hash | 同 IP 总落同一台 | 按身份证号固定窗口 |
| 一致性哈希 | Consistent Hash | 同 Key 落同一台,扩缩容影响小 | 按会员号固定客服,换人影响小 |
| 最短响应 | Least Response Time | 选历史响应最快的 | 谁办业务最快找谁 |
3.3 轮询(Round Robin)— 默认首选
原理
维护一个有序列表,请求按顺序依次分配:
请求 1 → A
请求 2 → B
请求 3 → C
请求 4 → A
...Nginx 配置
nginx
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
# 不写任何关键字,默认就是轮询适用场景
- 所有后端 配置相同
- 每个请求处理时间 差不多(都是查数据库返回 JSON)
不适用
- 机器配置差异大(老机器 2 核、新机器 32 核)
- 有的请求 10ms,有的 30 秒(长请求会占住连接)
生活例子
食堂 3 个窗口卖同一种盖饭,每个师傅手艺差不多、出餐时间差不多——轮流分流最公平。
3.4 加权轮询(Weighted Round Robin)
原理
给每台机器一个权重 weight,权重越高分得越多。
A: weight=5
B: weight=2
C: weight=1
每 8 个请求 ≈ A 拿 5 个,B 拿 2 个,C 拿 1 个Nginx 配置
nginx
upstream backend {
server 10.0.0.1 weight=5;
server 10.0.0.2 weight=2;
server 10.0.0.3 weight=1;
}适用场景
- 异构集群:新旧机器混部、不同规格云主机
- 灰度发布:新版本
weight=1,老版本weight=9
坑
- 权重是 静态的,不会根据实时 CPU 自动调整
- 权重拍脑袋容易不准——应结合压测数据
生活例子
银行 3 号窗是新来的实习生(weight=1),1 号窗是资深柜员(weight=5)——同样轮候,资深柜员多接几单才合理。
3.5 随机(Random)
原理
每次从后端池 随机 选一台。长期看趋近均匀,短期可能不均匀。
适用场景
- 实现简单、无状态、后端同质
- 客户端 LB 里偶尔使用
坑
- 短时间内可能「运气不好」全打到同一台
- 生产环境较少单独使用,多作为基准对比
生活例子
抽奖决定你去哪个窗口——大体公平,但可能连续三次都抽到同一个。
3.6 最少连接(Least Connections)
原理
维护每台后端的 当前活跃连接数,新请求发给连接数 最少 的那台。
时刻 T:
A: 12 个活跃连接
B: 3 个活跃连接 ← 新请求给 B
C: 7 个活跃连接Nginx 配置
nginx
upstream backend {
least_conn;
server 10.0.0.1;
server 10.0.0.2;
server 10.0.0.3;
}适用场景
- 请求处理时间 差异大(上传文件 vs 查缓存)
- 长连接 / WebSocket / gRPC streaming
- 后端会出现「慢请求占坑」
生活例子
超市收银台,经理看一眼——3 号队 2 人、7 号队 8 人,新顾客去 3 号。谁队短去哪,比死板轮询更合理。
与轮询对比(关键面试点)
| 场景 | 轮询 | 最少连接 |
|---|---|---|
| 请求都是 50ms | 都很好 | 略好,差别不大 |
| 10% 请求要 30s | 差:慢请求所在机器堆积 | 好:自动避开忙的机器 |
3.7 IP 哈希(IP Hash)
原理
对客户端 IP 做哈希,同一 IP 的请求总是落到同一后端。
nginx
upstream backend {
ip_hash;
server 10.0.0.1;
server 10.0.0.2;
}适用场景
- 老系统把 Session 存在 本机内存,必须粘性会话
- 无 Redis 时的临时方案
坑(重要!)
| 坑 | 说明 |
|---|---|
| NAT 共享 IP | 公司出口一个 IP,上千员工算「一个客户端」全落一台 |
| 移动网络 IP 变 | 4G/5G 切换基站,IP 变了,登录态丢失 |
| 后端扩缩容 | 节点数量变化,哈希环重算,大量用户「搬家」 |
| 分布不均 | 某些 IP 流量特别大(爬虫、大屏),单机热点 |
生活例子
按 身份证号后两位 固定窗口——同一个人每次来都找同一个柜员。
但一家人共用一个地址(NAT)就全挤在一个窗口;搬家(换 IP)后要重新分配柜员。
现代最佳实践
不要用 IP Hash 苟会话。把 Session 放到 Redis,用轮询或最少连接——更稳、更均匀。
3.8 一致性哈希(Consistent Hash)
原理(用生活例子理解)
普通哈希:hash(key) % N,N 台机器变 5 台变 6 台时,几乎所有 key 都要重新映射——灾难。
一致性哈希:把后端和 key 都映射到一个 环 上(0~2³²-1)。
环上的节点
A ●─────────● B
╲ ╱
╲ ╱
● C
key "user-42" 顺时针找最近的节点 → 落在 B加一台机器:只影响环上 相邻一小段 的 key,不是全部重来。
适用场景
- 分布式缓存(Memcached、Redis 集群路由)
- 同一 URL / 同一用户 ID 要打同一台以提升缓存命中
- 后端频繁扩缩容
Nginx 配置(需模块支持)
nginx
upstream backend {
hash $request_uri consistent;
server 10.0.0.1;
server 10.0.0.2;
}
# 或 hash $http_x_user_id consistent;虚拟节点(Virtual Nodes)
真实环境里每台物理机映射 多个虚拟节点 在环上,避免分布不均。
生活例子:不是只放一个「B 客服」在环上,而是放「B1、B2、B3」三个虚拟点,让环更均匀。
与 IP Hash 对比
| IP Hash | 一致性哈希 | |
|---|---|---|
| Key | 客户端 IP | 任意(User-ID、URL) |
| 扩缩容 | 几乎全部重映射 | 只影响局部 |
| 可控性 | 低 | 高(自选 key) |
3.9 最短响应时间(Least Response Time)
原理
结合 活跃连接数 和 历史平均响应时间,选「预计最快完成」的节点。
HAProxy 支持较好;Nginx 需第三方或 Plus。
适用场景
- 后端性能差异 动态变化(有的机器正在 Full GC)
- 对延迟敏感的业务
生活例子
经理不只看队长短,还看每个柜员 最近平均办一单要多久——队短但柜员特别慢,也不给你。
3.10 算法选型速查表
| 你的场景 | 推荐算法 |
|---|---|
| 同质 Web API,短请求 | 轮询 |
| 新旧机器混部 | 加权轮询 |
| 长短请求混合、上传下载 | 最少连接 |
| 要会话粘性(legacy) | 一致性哈希 > IP Hash;最好改无状态 |
| 缓存集群路由 | 一致性哈希 |
| 灰度 10% 流量到新版本 | 加权轮询(新 weight 小) |
| 微服务 gRPC 长流 | 最少连接 |
3.11 动手实验
bash
# 模拟 3 台后端,发 12 个请求,看轮询分布
python3 code/lb_simulator.py --algorithm round_robin --requests 12
# 模拟处理时间不均时,最少连接 vs 轮询
python3 code/lb_simulator.py --algorithm least_connections --uneven
# 同一用户 ID 是否总落同一台
python3 code/lb_simulator.py --algorithm consistent_hash --key user-42 --requests 10打开 03_algorithms/demo.html 可视化对比。
3.12 面试题精选
轮询和加权轮询区别?
→ 轮询均等;加权按 weight 比例分配,适应异构机器。什么时候用 least_conn?
→ 请求耗时差异大、长连接场景,避免慢请求导致某台堆积。一致性哈希解决什么问题?
→ 节点增减时避免大规模 key 重映射;适合缓存路由。ip_hash 有什么问题?
→ NAT 不均、移动 IP 变、扩缩容漂移;应优先无状态 + 共享 Session。
3.13 一句话总结
轮询打天下,异构用加权,快慢不一 least_conn,缓存路由一致性哈希,千万别用 IP Hash 当长期方案。
下一章 → 04 · 健康检查:怎么知道后端「病了」?怎么优雅地让它休息?
🎬 可视化演示
打开 03_algorithms/demo.html,点击不同算法按钮,观察 20 个请求如何落到 4 台后端。
🎬 可视化演示
演示加载缓慢或样式异常?点此在新标签页打开 ↗