本页课程原文(点开阅读)

负载均衡

课程(6 节,按顺序学)

第 1 课 · 为什么要有负载均衡

入门 · 约 8 分钟

本课目标:搞清负载均衡解决的是什么问题,以及 VIP 是什么。

一台服务器扛不住,也怕挂

流量大了,一台服务器会遇到两个问题:

① 扛不住——CPU/带宽/连接数到顶了
② 单点故障——这台挂了,服务就没了

负载均衡(LB)解决的就是这两件事:把一个入口地址(VIP,Virtual IP)背后的流量分散到一组后端服务器,而客户端完全不知道背后到底有几台、是哪几台。

★ VIP:客户端只认这一个地址

客户端始终只连一个虚拟 IP(VIP)——不管背后有 3 台还是 30 台后端,加机器、减机器、换机器,客户端毫无感知。

★ 这跟 DNS 模块的 CNAME 有点像(对外一个名字,背后可以换)——但 LB 是实时按每一条流量做决策,DNS 是查询时决定一次。

动手:看流量怎么被分散

去流量仿真页,随便发几条流量,看它们怎么落到不同的后端上。

实验重点

  • ★ 负载均衡解决两件事:扛不住 + 单点故障
  • ★ VIP 是客户端唯一认识的地址,后端可以随时增减而不影响客户端
  • 跟 DNS 的 CNAME 不同:LB 是实时按每条流量决策,不是查询时决定一次

第 2 课 · ★★★ 三层/四层/七层:核心差别是决策粒度

进阶 · 约 12 分钟

本课目标:这是整个模块的核心:三层看 IP,四层看连接,七层看请求。

★★★ 不只是看的头不一样

很容易把三层/四层/七层的差别理解成看的头不一样,这没错,但更关键的是决策的粒度:

| 层级 | 看什么 | 决策粒度 |
|---|---|---|
| 三层(NLB) | 只看 IP | 同一个客户端——不管开几个端口,永远同一台 |
| 四层(CLB) | 四元组(IP+端口) | 同一条连接——换一条连接可能换台 |
| 七层(ALB) | HTTP 内容 | 同一个请求——同一条连接的两个请求可以不同台 |

★★★ 七层能做到请求级,是因为它压根不是转发,而是反向代理:先接住客户端的连接,解析出请求,自己另开一条连接去问后端。客户端到 LB、LB 到后端,是两条独立的连接。

★★ 为什么三层/四层做不到请求级

三层/四层是转发(forwarding),不是代理——包到了就按规则送到某台后端,LB 不终结这条连接,也不会去解析里面是什么请求。

一条 TCP 连接从建立到断开,中间所有的包必须去同一台后端——否则后端收到的是断章取义的一半数据,直接就错了。所以三层/四层的决策粒度下限就是一条连接,改不了。

动手:亲眼看到粒度的差别

去流量仿真页:
① 场景 ①(三层):同一客户端两个端口,看是不是永远同一台
② 场景 ③(七层):同一条连接,先发 /api/users 再发 /static/logo.png,看是不是能落到不同后端

实验重点

  • ★★★ 决策粒度:三层=客户端,四层=连接,七层=请求
  • ★★ 七层能做到请求级,是因为它是反向代理——两条独立的连接
  • 三层/四层是转发,不终结连接,粒度下限就是一条连接

第 3 课 · ★★ 负载均衡算法

进阶 · 约 10 分钟

本课目标:几种最常见算法,以及各自适合什么场景。

最简单的两种:轮询 / 加权轮询

轮询(Round Robin):一个一个来,A、B、C、A、B、C……

加权轮询(Weighted RR):机器性能不一样时用——权重 3 的机器,轮询序列里就多出现 3 次。

★ 两者共同的局限:都不看后端实际负载——哪怕某台后端已经在处理慢查询累成狗,轮询该轮到它还是轮到它。

★ 最少连接数:看实际负载

最少连接数(Least Connections):新连接给当前挂着连接最少的那台。

★ 更贴近真实负载,但要求 LB 一直维护每台后端的连接计数——比轮询多一点状态要维护。

★★ 哈希类:同一个 key 永远同一台

取模哈希 / 一致性哈希:拿 key(IP,或者四元组)算一个哈希值,映射到某台后端——同一个 key 每次算出来的都是同一个结果。

★ 这是确定性的来源,跟轮询/最少连接数不一样——轮询和最少连接数的结果取决于历史(前面来过多少请求),哈希类算法的结果只取决于 key 本身。

★★ 两种哈希的差别留到第 5 课细讲——取模哈希扩容时会大洗牌,一致性哈希不会。

动手:切换算法对比

去配置负载均衡器页切换算法,回流量仿真页用同一批流量跑一遍,对比分布结果。

实验重点

  • 轮询/加权轮询:简单,但不看实际负载
  • 最少连接数:看实际负载,但要维护连接计数
  • ★★ 哈希类:确定性——同一个 key 永远同一个结果,不取决于历史

第 4 课 · ★★ 健康检查

进阶 · 约 8 分钟

本课目标:LB 怎么知道该不该继续把流量发给某台后端。

★★ 健康检查就是 LB 自己发的探测流量

LB 会定期主动探测每台后端(比如发一个 HTTP GET /health,或者就是普通的 TCP 连接尝试),根据探测结果判断这台后端现在还能不能接流量。

★★★ 注意:这是LB 自己发的普通请求,不是什么信令协议在多台设备之间同步状态——跟负载均衡没有控制面是同一件事:LB 只有 traffic,健康检查也只是另一种 traffic,不是别的东西。

★ 不健康的后端会被自动摘除

一旦某台后端被判定不健康,新的流量不会再发给它(已经在它上面的老连接一般不会强行打断,但这里的教学重点是新流量)。

健康检查恢复正常之后,这台后端会被自动重新加入——不需要人手工干预。

动手:看流量绕开不健康的后端

当前场景 ④ 健康检查:Backend2 已经被标记成不健康。去流量仿真页连续发几条流量,看是不是全都绕开了 Backend2。

实验重点

  • ★★★ 健康检查是 LB 自己发的探测流量,不是控制面协议
  • ★ 不健康自动摘除、恢复自动加回——不需要人工干预
  • 这正是负载均衡没有控制面、只有 traffic 的一个具体例子

第 5 课 · ★★ 一致性哈希:为什么扩容抖动小

进阶 · 约 10 分钟

本课目标:取模哈希扩容会大洗牌,一致性哈希不会——原理是什么。

★★ 取模哈希的问题:分母一变,全洗牌

取模哈希:backend = hash(key) % 后端数。

问题就在这个 % 后端数——后端数从 3 变成 4,几乎每一个 key 算出来的余数都会变(除法的分母变了),于是几乎所有客户端都要换一台后端。

★ 换后端意味着什么?如果这些连接是有状态的(比如登录会话缓存在本地),几乎所有用户的会话在扩容那一刻全部失效。

★★★ 一致性哈希:把后端和 key 都扔进一个环里

把一个很大的数字空间画成一个环(比如 0~10000),每台后端在环上占几个点(哈希它的名字),每个 key 也在环上有个位置(哈希 key 本身)。

规则:从 key 的位置顺时针走,碰到的第一个后端的点,就是它。

★★★ 加一台新后端,只是在环上多了几个新点——只有原来顺时针恰好落在这几个新点前面的那一小段 key 会改主意,其余所有 key 的归属完全不受影响。

动手:亲眼数一数抖动差多少

当前场景 ⑤ 一致性哈希:先用取模哈希跑一遍 5 个客户端,记住映射;点「加一台后端」;再跑一遍,数一数变了几个。

换成一致性哈希,重复一遍,对比抖动数量。

实验重点

  • ★★ 取模哈希:% 后端数,分母一变几乎全洗牌
  • ★★★ 一致性哈希:后端和 key 都在一个环上,加后端只影响一小段
  • 抖动小意味着扩容时受影响的用户/会话少

第 6 课 · ★★ 会话保持:为什么只有七层能做

进阶 · 约 10 分钟

本课目标:Cookie 粘性怎么工作,以及它的代价。

★★ 有些应用需要同一个用户始终同一台

如果后端服务器把用户状态(比如购物车、登录态)存在自己本地内存里,而不是存进共享的数据库/缓存,那这个用户就必须每次都回到同一台——换一台服务器,本地内存里的状态就丢了。

这种粘性叫会话保持(Session Affinity)。

★★★ 为什么只有七层能做

会话保持最常见的实现是在 Cookie 里塞一个标记——而读 Cookie 需要解析 HTTP 头,这是七层才有的能力。

流程:
① 第一次请求没带这个 Cookie → 按正常算法选一台,顺手在响应里塞一个 Cookie,记住选的是哪台
② 下次请求带着这个 Cookie 回来 → 不管算法本该选谁,直接粘回记住的那台

★ 四层能做的粘性是按源 IP 粘(本质就是 IP 哈希),对着 NAT 后面一大群用户共享同一个公网 IP 的场景就不准了——这也是七层 Cookie 粘性更精确的原因:粘的是这个用户,不是这个 IP。

动手:看粘性怎么覆盖轮询

当前场景 ⑥ 会话保持:第一次发请求(不带 cookie),记下拿到的 cookie;第二次带着这个 cookie 发——即使轮询本该轮到别的后端,也应该粘回第一次那台。

实验重点

  • 会话保持解决的问题:后端把用户状态存在本地内存里
  • ★★★ 七层靠读 Cookie 做粘性,四层最多只能按源 IP 粘(不精确)
  • ★ 更彻底的解法是后端别把状态存本地——存共享缓存,粘性就不需要了
冀ICP备2026021556号-2|冀公网安备13068302000206号