mcpField
L
load-balancing

load-balancing

github.com/proyecto26云与 DevOps116319 次安装3 天前更新
代码仓库

关于 load-balancing

面向系统设计者的负载均衡技能,帮助在后端池间分配请求并规划健康检查与故障处理。涵盖 L4、L7、分配算法和高可用拓扑,并强调避免恢复节点过载及均衡器成为单点故障。

主要功能

  1. 01选择 L4 或 L7 均衡
  2. 02比较请求分配算法
  3. 03规划主动-主动或主动-被动拓扑
  4. 04定义健康检查与连接排空
  5. 05处理慢启动和重试放大

适用场景

  1. 01将请求分发到多个后端
  2. 02为后端池设计健康门控
  3. 03规划均衡器高可用与故障切换

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/proyecto26/system-design-skills --skill load-balancing

安装后在 Claude Code 中输入/load-balancing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
deep-dive.md
references/providers/
aws.md
azure.md
gcp.md
generic.md

详细介绍

负载均衡

将传入请求分配到一组相同的后端,让任何一台服务器都不会成为瓶颈或单点故障。如果配置不当,负载均衡器本身就会成为它原本要消除的单点故障(SPOF),将流量路由到已宕机的服务器,或在某个后端已不堪重负时仍不断向其发送请求,加剧故障。

适用场景

当多个后端承担相同职责,且流量必须在它们之间分配时;当需要消除单一入口这一单点故障时;当需要增减服务器而不让客户端察觉时(这是实现无状态层和自动扩缩容的基础);或者需要在私有服务器集群前设置一个公共地址,并在同一处处理 TLS 终止、健康检查和路由时,都可以使用负载均衡器。

不适用场景

如果单个后端能够轻松应对峰值负载,就暂时不需要负载均衡器——增加它会引入新组件、新故障模式和新的运维对象(YAGNI)。如果真正的瓶颈是数据库或单个热点分片,那么在 Web 层前放置负载均衡器毫无帮助;应先诊断实际的限制因素(→ back-of-the-envelope)。跨区域流量调度通常通过边缘的 DNS/任播实现,而不是 L4/L7 负载均衡器(→ content-delivery)。针对客户端的请求限流属于 resilience-failure 负责的策略问题,而非负载均衡算法的问题。

先明确需求

  • 协议和所需层级 — 需要原始 TCP/UDP 吞吐量(L4),还是需要根据路径/主机/标头/Cookie 进行 HTTP 感知路由(L7)?这决定负载均衡器类型。
  • 状态 — 后端是无状态的,还是会话驻留在某台服务器上(因此必须启用会话亲和性)?将状态移出几乎总是更好的选择。
  • 峰值 QPS 和连接数 — 是一条高吞吐连接流,还是大量短请求?这会影响算法和负载均衡器的容量规划(→ back-of-the-envelope)。
  • 健康信号 — “健康”的定义是什么(接受 TCP 连接?/healthz 返回 200?检查深层依赖?),以及故障节点必须多快从池中移除?
  • TLS — 在负载均衡器处终止 TLS(减轻后端负担、检查 L7),还是端到端透传(合规要求/mTLS)?

选项

检查层级

  • **L4(传输层):**根据 IP/端口进行路由;通过 NAT 或 DSR 转发数据包,不读取负载。适用于需要原始吞吐量、使用非 HTTP 协议或希望将额外延迟降至最低的场景。
  • **L7(应用层):**终止连接,读取 HTTP(主机、路径、标头、Cookie),然后进行路由。适用于需要基于内容的路由、按路由划分后端池、TLS 终止或重写请求的场景。

分配算法

  • **轮询 / 加权轮询:**均匀轮换,并按容量加权。适用于负载均匀的无状态后端。
  • **最少连接 / 最短响应时间:**将请求发送到最空闲的节点。适用于请求开销差异较大的场景(长连接、混合工作负载)。
  • **IP 哈希 / 一致性哈希:**将客户端(或键)映射到固定后端。适用于无需在服务器端存储会话状态的亲和性,或需要保持缓存局部性的场景。
  • **随机(两次选择):**随机选取两个节点,并选择负载较轻的那个——成本低,在大规模场景下效果出奇地均匀。

拓扑结构

  • **主备模式:**一个负载均衡器提供服务,发生故障时由备用节点接管 VIP。实现高可用性较简单。
  • **主动-主动模式:**多个负载均衡器共同分担负载(通过 DNS 或任播)。消除负载均衡器自身的单点故障,并增加容量余量。

**反向代理的作用:**L7 负载均衡器同时也是反向代理——它是唯一的公共入口,隐藏后端,终止 TLS,压缩和缓存内容,并集中处理路由。即使只有一个后端,反向代理也能带来这些好处,因此仍值得使用;多后端场景下的负载均衡只是同一组件的另一种用途。

权衡

选项解决的问题带来的问题何时更改
L4 负载均衡最大吞吐量、低延迟,支持任意协议无法识别内容;不支持路径/标头路由,也不能检查 TLS需要基于内容路由或终止 TLS → L7
L7 负载均衡内容路由、TLS 卸载、重写、可观测性延迟和 CPU 开销更高;会终止连接(状态更多)原始吞吐量占主导且路由简单 → L4
轮询极其简单,适用于工作负载均匀的情况忽略实际负载;慢节点仍会分到请求请求开销差异很大 → 最少连接数
最少连接数能适应请求开销不均需要实时连接状态;可能让流量集中到刚恢复的节点后端性能均一 → 轮询就足够
IP/一致性哈希无需会话存储即可实现亲和性和缓存局部性分布不均;后端池变更时会重新平衡可以将状态外置 → 轮询 + 共享存储
会话保持目前可用于有状态后端破坏均匀分布,使缩容更复杂,节点故障时会丢失会话状态可以迁移到 Redis/DB → 取消亲和性
主动-被动为负载均衡器提供简单的高可用备用节点闲置;故障转移存在间隙(数秒)需要无间隙的容量余量 → 主动-主动

压力下的行为

负载均衡器位于所有请求的路径上,因此它的故障模式就是整个系统的故障模式。

  • 健康检查导致流量骤增(典型陷阱): 后端恢复后,负载均衡器将其标记为健康,全部流量便涌向这个单一的冷启动节点——缓存为空、JIT 尚未预热、连接队列已满——导致它未能通过下一次健康检查并退出,反复振荡(状态抖动)。过于激进的检查实际上可能会 DDoS 正在恢复的服务。可通过慢启动 / 逐步增加连接数、设置宽松的失败阈值(驱逐前连续失败 N 次,重新接纳前连续成功 M 次)、检查抖动,以及在依赖路径上设置断路器来缓解(→ resilience-failure)。
  • 重试放大: 负载均衡器(或客户端)会将失败的请求重试到其余健康节点,因此丢失一个节点可能引发级联故障,幸存节点不仅要承担该节点的负载,还要处理重试请求。限制重试次数;使用带抖动的退避策略(由 resilience-failure 负责)。
  • 负载不均 / 热点后端: 长连接或会话保持会使负载集中在少数节点上;轮询无法发现这一点。应监控每个后端的利用率,而不只是整体指标。
  • 负载均衡器成为单点故障: 单个负载均衡器故障会导致一切停摆。采用主动-主动或主动-被动模式,并配置快速 VIP/任播故障转移。
  • 重连风暴: 负载均衡器重启时,所有客户端会同时重连。应分阶段排空连接,并设置连接数限制。

监控: 每个后端的请求速率和延迟(p99)、健康主机数、健康检查通过/失败情况和状态抖动率、连接数、负载均衡器与后端的 5xx 错误率(两者差异有助于定位故障),以及活动连接分布。

如何应用

  1. 明确输入信息 — 回答 先澄清 中的问题:协议/层级、后端是否无状态、峰值 QPS 和连接数、“健康”的含义,以及 TLS 策略。这些信息决定之后的所有选择。
  2. 根据权衡表选择层级和算法 — 需要原始吞吐量或处理非 HTTP 流量时选择 L4;需要按内容路由或卸载 TLS 时选择 L7。无状态后端配置一致时,默认选择轮询;仅当请求开销有所不同才考虑最少连接;只有状态暂时无法迁移时才使用基于哈希的亲和性。
  3. 设置关键参数 — 明确编写健康检查配置(方法、路径、预期状态码、间隔、失败/恢复阈值)和连接池的排空延迟;启用慢启动,让恢复中的节点逐步接收流量,而不是一下子承受全部流量。
  4. 对方案进行压力测试 — 逐一检查故障模式:健康检查请求风暴、重试放大、后端过热,以及负载均衡器成为单点故障(SPOF)。采用主动-主动(或通过快速 VIP/任播故障转移实现主动-被动),避免负载均衡器成为新的单点故障。
  5. 用数字确定容量 — 确认负载均衡器能够处理峰值 QPS 和并发连接,并验证真正的容量瓶颈是后端集群,而非负载均衡器。从 back-of-the-envelope 获取每台服务器的 QPS 和连接内存占用数据。
  6. 选择提供商 — 默认使用通用方案;如果指定了云服务商,请查阅其提供商文件,了解托管服务对应方案和限制。
  7. 在回答中说明权衡 — 提供一张 Decision | Solves | Worsens | Change it when… 表格,为此处做出的每项选择各列一行(例如,所选方案、存储、故障策略);最后一列填写具体的触发条件(一个数值或可观察信号)。然后指出最先会出现的故障。

应做与不应做

应做

  • 将会话状态存入共享存储,以便使用普通轮询和自动扩缩容。
  • 明确规定健康检查,并有意识地选择浅层检查还是深层检查。
  • 采用主动-主动或主动-被动模式运行负载均衡器,避免其成为 SPOF。
  • 启用慢启动,并设置较宽松的失败/恢复阈值,防止状态抖动。
  • 监控各后端的利用率,而不只是整体利用率,以发现过热节点。

不应做

  • 单个后端已能处理峰值负载时,不要增加负载均衡器(YAGNI)——反向代理或许仍有价值,但无需在多个后端之间进行负载均衡。
  • 不要让针对缓慢依赖项的深层健康检查一次性剔除整个集群。
  • 状态可以直接迁出时,不要急于使用粘性会话。
  • 不要盲目向剩余节点重试;应限制重试次数,并使用退避/抖动。
  • 在确认后端集群有容量瓶颈之前,不要假定负载均衡器是瓶颈。

关键数据

现代软件负载均衡器(HAProxy/Nginx/Envoy)每个实例可处理每秒数万次请求和数千个并发连接,通常远高于单个 Web/应用节点的处理能力,因此很少会成为首要瓶颈。应根据峰值 QPS 和并发连接数确定其容量,并确认真正的容量瓶颈是后端集群,而非负载均衡器。每台服务器的 QPS、连接内存开销和峰值系数计算均见 back-of-the-envelope——此处不再重复,请从中提取数据,为连接池和负载均衡器确定容量。

接口示意

负载均衡本身没有独立的请求/响应契约,但有两项配置会对系统产生重大影响,值得明确记录:

  • 健康检查: 方法 + 路径 + 预期状态码 + 间隔 + 阈值,例如 GET /healthz → 200, every 5s, unhealthy after 3 fails, healthy after 2 passes。应有意识地决定将 /healthz 设为浅层检查(进程存活)还是深层检查(检查 DB)——针对缓慢依赖项的深层检查一旦失败,就可能一次性剔除整个集群。
  • 后端池/目标组: host:port 目标、权重,以及缩容时使用的排空/注销延迟,以便正在处理的请求能够完成。

负载均衡如何实现无状态层

只有在任何服务器都能处理任何请求时,才能将请求自由分发到可互换的服务器上——也就是说,服务器上不保存会话状态。将会话状态放入共享存储(Redis/DB),这样负载均衡器就能使用普通轮询,随时添加或移除节点,并让自动扩缩组增减服务器池。只有在状态暂时无法迁移时,才将会话粘滞作为备用方案,但这会牺牲分布均匀性和轻松缩容的能力。水平扩展和无状态层由 scaling-evolution 负责;本技能提供实现路由的机制。

选择提供商

默认使用上述通用方案。如果用户指定了云服务,请阅读 references/providers/<provider>.md,了解托管服务映射、配额/限制和提供商特定的权衡。如果该提供商没有对应文件,则采用通用方案。

图示

要将请求路径(客户端 → 负载均衡器 → 后端服务器池)或健康检查/故障转移流程可视化,请使用插件内的 architecture-diagram 技能。也可以用 client → [LB] → {web1, web2, web3} → shared state 快速绘制内联草图辅助推理;不要嵌入 Mermaid。

相关构建模块

  • scaling-evolution — 为本技能提供基础:它负责无状态层以及水平扩展与垂直扩展;本技能则提供路由机制,让该服务器集群可被访问。
  • resilience-failure — 与本技能配合使用,适用于负载均衡器可能放大故障的情况;相关概念归此技能负责:重试/退避/抖动、断路器、故障转移和限流可用于解决健康检查风暴和重试风暴。
  • content-delivery — 跨区域流量场景下的替代方案:当“均衡”实际上是将用户引导至最近的区域时,正确的工具是在边缘进行地理位置/DNS/任播路由(由该技能负责),而不是 L4/L7 负载均衡器。
  • back-of-the-envelope — 依赖本技能提供的 QPS、连接数和峰值系数数据,用于确定服务器池和负载均衡器的规模。
  • system-design — 当设计从一台服务器扩展到多台时,负责将请求路由到此处的协调器。

参考资料

  • references/deep-dive.md — L4 NAT 与 DSR、L7 终止的工作原理、算法内部细节(包括用于亲和性的 一致性哈希)、健康检查调优与慢启动、连接排空、TLS 终止与透传。配置负载均衡器时,请详细阅读。
  • references/providers/{generic,aws,azure,gcp}.md — 各环境的服务映射、限制和注意事项。

评论

支持 Markdown