# 负载均衡基础

> 数据包、网络、服务器、L4 和 L7 负载均衡基础

---

LLMS 索引： [llms.txt](/zh/llms.txt)

---

<!-- Generated by scripts/generate-haproxy-docs.py from pinned upstream text. -->

本文旨在向所有尚未了解 HAProxy 的用户以及希望重新认识该软件（尤其是熟悉旧版本的用户）提供入门引导。本文主要目的在于为用户提供所有要素，以判断 HAProxy 是否就是他们在寻找的产品。高级用户可能在此发现某些解决方案的片段，仅因此前未意识到某项新功能的存在。此外，本文还提供了部分容量规划信息，说明了产品的生命周期，并对部分功能重叠的产品进行了对比。

本文不提供任何配置帮助或提示，但说明了在哪里可以找到相关文档。本指南以 HAProxy 侧边栏中的扁平主题页面序列形式呈现。

负载均衡是指将多个组件聚合在一起，以实现总处理能力超过单个组件的处理能力，且无需终端用户干预，并具备可扩展性。这使得在单个组件完成一次操作所需的时间内，能够同时执行更多操作。然而，单个操作在任一时刻仍只在单个组件上执行，且不会比不使用负载均衡时更快。要利用所有组件并充分受益于负载均衡，始终需要至少与可用组件数量相当的操作数，以及高效的负载均衡机制。一个典型的例子是高速公路的车道数量，它能够在不提高单车速度的前提下，使更多车辆在相同时间段内通过。

负载均衡示例：

- 多处理器系统中的进程调度
- 链路负载均衡（例如 EtherChannel、Bonding）
- IP 地址负载均衡（例如 ECMP、DNS 轮询）
- 服务器负载均衡（通过负载均衡器实现）

执行负载均衡操作的机制或组件称为负载均衡器。在 Web 环境中，这些组件通常被称为“网络负载均衡器”，但更常见的是直接称为“负载均衡器”，因为此类应用无疑是负载均衡最广为人知的场景。

负载均衡器可在以下层级发挥作用：

- 在链路层：这称为链路负载均衡，其原理是选择将数据包发送至哪个网络链路；

- 在网络层：这称为网络负载均衡，其原理是选择一系列数据包所遵循的路由路径；

- 在服务器层：这称为服务器负载均衡，其作用是决定由哪台服务器处理连接或请求。

存在两种不同的技术，各自满足不同需求，部分能力有所重叠。无论采用哪一种，都需要牢记：负载均衡会使流量偏离其自然流向，而这样做总是需要至少一定程度的谨慎，才能在所有路由决策之间保持所需的一致性。

第一种技术在数据包层面运行，对数据包进行或多或少的独立处理。输入与输出数据包之间存在一对一的关系，因此可以使用常规网络嗅探工具在负载均衡器的两侧追踪流量。该技术可以非常廉价且极其快速。它通常通过硬件（ASIC）实现，可达到线路速率，例如执行 ECMP 的交换机。通常为无状态，但也支持有状态（考虑数据包所属会话），称为第 4 层负载均衡（L4），若数据包未被修改，还可支持 DSR（直接服务器返回，无需再次经过负载均衡器），但几乎不具备内容感知能力。该技术非常适合网络层负载均衡，尽管有时也用于高速场景下非常基础的服务器负载均衡。

第二种技术处理会话内容。它要求重组输入流并将其作为整体处理；内容可以修改，输出流则被分段为新的数据包。因此，这类操作通常由代理完成，此类代理常被称为第 7 层负载均衡器（L7）。负载均衡器两侧是两条相互独立的连接，输入与输出数据包的大小和数量没有对应关系。客户端与服务器也不必使用相同协议（例如 IPv4 与 IPv6、明文与 SSL）。这种操作始终是有状态的，返回流量必须经过负载均衡器。额外的处理会带来开销，因此并非总能达到线速，尤其是在小数据包时。另一方面，它提供了广泛的可能性，通常由纯软件实现，即使部署在硬件设备中也是如此。该技术非常适合服务器负载均衡。

基于数据包的负载均衡器通常以直通模式部署，因此被安装于流量的正常路径上，并根据配置改变其流向。返回流量不一定经过负载均衡器。为将流量导向正确目的地，可能需要对网络目标地址进行修改。在此情况下，必须确保返回流量经过负载均衡器。若路由无法实现此目的，负载均衡器也可将数据包的源地址替换为其自身地址，以强制返回流量经过它。

基于代理的负载均衡器以拥有独立 IP 地址和端口的服务器形式部署，无需更改架构。有时需要对应用程序进行一些调整，以确保客户端正确地被引导至负载均衡器的 IP 地址，而非直接连接到服务器。部分负载均衡器可能需要修改某些服务器的响应，以实现这一目标（例如，HTTP 重定向中使用的 HTTP Location 头字段）。某些基于代理的负载均衡器可能拦截其并不拥有的地址的流量，并在连接服务器时伪造客户端地址。这使得它们可以像普通路由器或防火墙一样部署，以近乎与基于数据包的负载均衡器相同的直通模式运行。对于同时支持数据包模式和代理模式的产品而言，这一点尤为实用。在此情况下，DSR 显然仍不可行，返回流量仍必须路由回负载均衡器。

一种高度可扩展的分层架构包括：前端路由器接收来自多个负载均衡链路的流量，并使用 ECMP 将流量分发至第一层的多个有状态的基于数据包的负载均衡器（L4）。这些 L4 负载均衡器再将流量转发至数量更多的基于代理的负载均衡器（L7），后者需解析流量内容以决定最终接收流量的服务器。

组件数量和流量路径的增加提高了故障风险；在非常大型的环境中，永久存在少数处于修复或更换状态的故障组件甚至很正常。若负载均衡未考虑整个堆栈的健康状况，将显著降低可用性。因此，任何合理的负载均衡器都会验证其计划分发流量的目标组件是否仍处于活跃且可达状态，并停止向故障组件分发流量。这可通过多种方式实现。

最常见的方法是定期发送探测，以确保组件仍处于正常运行状态。这些探测被称为“健康检查”。健康检查必须能够代表所要解决的故障类型。例如，基于 ping 的检查无法检测到 Web 服务器已崩溃且不再监听端口的情况，而连接到该端口的检查则可以验证这一点，更高级的请求甚至可以验证服务器是否仍在正常工作，以及其所依赖的数据库是否仍可访问。健康检查通常包含若干次重试，以应对偶尔的测量误差。健康检查之间的间隔必须足够短，以确保在发生错误后，故障组件不会被继续使用过长时间。

其他方法包括对发送至目标的生产流量进行采样，以观察其是否被正确处理，并剔除返回不恰当响应的组件。然而，这种方法需要牺牲一部分生产流量，这并不总是可接受的。将这两种机制结合使用，可以兼顾两者的优点：两者均用于检测故障，而仅通过健康检查来检测故障的结束。最后一种方法涉及集中式报告：中央监控代理定期向所有负载均衡器更新所有组件的状态。这使所有组件都能获得基础设施的全局视图，尽管有时准确性或响应性可能较低。该方法最适合负载均衡器和服务器数量较多的环境。

第 7 层负载均衡器还面临另一个挑战，即会话粘性或持久性。其原理是，它们通常必须将来自同一来源（例如终端用户）的多个后续请求或连接导向同一目标。最广为人知的例子是在线商店的购物车。如果每次点击都导致新的连接，用户必须始终被发送到保存其购物车的服务器。内容感知能力使得更容易在请求中发现某些元素，以确定将请求交付给哪台服务器，但这并不总是足够。例如，以源地址作为挑选服务器的键时，可以决定使用基于哈希的算法，通过将地址除以可用服务器数量，使特定 IP 地址始终发送到同一服务器。但如果某台服务器发生故障，结果就会改变，所有用户会突然被发送到其他服务器并丢失购物车。解决办法是记住所选的目标：以后每次遇到同一访问者时，无论可用服务器数量如何，都将其导向同一服务器。该信息可存储在负载均衡器的内存中；若它不是唯一的负载均衡器，则可能需要复制到其他负载均衡器。也可通过多种方式将信息存储在客户端的内存中，前提是客户端能在每次请求中将其带回（例如插入 Cookie、重定向到子域名等）。该机制还带来了无需依赖不稳定或分布不均的信息（如源 IP 地址）的额外好处。这实际上是采用第 7 层负载均衡器而非第 4 层的最强有力理由。

为了提取诸如 Cookie、Host 头字段、URL 等信息，负载均衡器可能需要解密 SSL/TLS 流量，甚至在将流量转发至服务器时重新加密。这一高开销操作解释了为何在某些高流量基础设施中，有时会存在大量负载均衡器。

由于第 7 层负载均衡器可能对流量执行多项复杂操作（如解密、解析、修改、匹配 Cookie、决定将请求转发至哪个服务器等），它确实可能引发诸多问题，且常常被误认为是许多问题的根源，而实际上它只是暴露了原本就存在的问题。通常会发现服务器不稳定，周期性地上下线；对于 Web 服务器而言，可能其返回的页面中包含硬编码的链接，导致客户端绕过负载均衡器直接连接至特定服务器；或者在高负载下响应时间极长，引发超时。因此，日志记录是第 7 层负载均衡中极为关键的环节。一旦出现故障报告，重要的是弄清负载均衡器是否做出了错误决策，如果是，原因是什么，以便不再发生。

---

反链：

- [HAProxy](/zh/docs/haproxy/)
- [资源](/zh/docs/haproxy/resources/)
