# HAProxy 是什么及其实现原理

> HAProxy 的角色、边界、事件驱动架构及请求处理模型

---

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

---

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

HAProxy 用于指代产品，而 HAProxy 用于指代可执行程序、软件包或进程。然而，两者常被互换使用，且均发音为 H-A-Proxy。早期，“HAProxy”曾代表“高可用性代理”，名称以两个独立单词书写，但如今其含义已仅限于“HAProxy”。

## 3.1. HAProxy 是与非 {#section-3-1}

HAProxy 是：

- TCP 代理：可从监听套接字接收 TCP 连接，连接至服务器，并将这两个套接字绑定在一起，从而实现双向流量传输；支持任一侧使用 IPv4、IPv6 或 Unix 套接字，因此可提供一种简便方式，实现不同地址族之间的地址转换。

- 一个 HTTP 反向代理（在 HTTP 术语中称为“网关”）：它表现为一个服务器，通过监听 TCP 套接字接收连接上的 HTTP 请求，并使用不同的连接将这些请求转发至服务器。它可在任一侧使用任意组合的 HTTP/1.x 或 HTTP/2，并在使用 ALPN 通过 TLS 时自动检测每侧所使用的协议。

- SSL 终止器 / 初始化器 / 卸载器：客户端连接、服务器连接，或两者均可使用 SSL/TLS。可根据名称（SNI）应用大量设置，且可在不重启的情况下动态更新。此类配置具有极强的可扩展性，已有部署报告支持数万至数十万张证书。

- TCP 正常化器：由于连接由操作系统本地终止，双方之间不存在关联，因此无效数据包、异常标志组合、窗口通告、序列号异常、不完整连接（如 SYN 洪水）等异常流量不会传递到另一方。这可保护脆弱的 TCP 栈免受协议攻击，同时允许在不修改服务器 TCP 栈设置的前提下，对客户端连接参数进行优化。

- HTTP 正常化器：当配置为处理 HTTP 流量时，仅允许完整且有效的请求通过。这可有效防范多种基于协议的攻击。此外，对于规范中允许容忍的协议偏差，会进行修正，以避免其在服务器端引发问题（例如，多行头）。

- 一个 HTTP 修复工具：可用于修改、修复、添加、删除或重写 URL，以及任意请求或响应头。这有助于解决复杂环境中的互操作性问题。

- 基于内容的转发：可根据请求中的任意元素决定将请求或连接转发至哪个服务器。因此，可在同一端口上处理多种协议（例如 HTTP、HTTPS、SSH）。

- 服务器负载均衡器：可对 TCP 连接和 HTTP 请求进行负载均衡。在 TCP 模式下，负载均衡决策针对整个连接作出。在 HTTP 模式下，决策针对每个请求作出。

- 流量调节器：可在多个位置实施速率限制，防止服务器过载，根据流量内容调整流量优先级，甚至通过标记数据包将此类信息传递至下层及外部网络组件。

- 防护 DDoS 和服务滥用：可针对每个 IP 地址、URL、Cookie 等维护大量统计信息，检测到滥用行为时采取动作（如降低攻击者速率、阻止其访问、将其引导至过时内容等）。

- 网络故障排查的观察点：由于日志中报告的信息精度较高，常用于缩小某些网络相关问题的排查范围。

- HTTP 压缩卸载器：可对服务器未压缩的响应进行压缩，从而降低客户端在连接质量较差或使用高延迟移动网络时的页面加载延迟。

- 缓存代理：可将响应缓存在内存中，使后续对同一对象的请求无需再次从服务器进行网络传输，只要该对象仍存在且有效即可。但该代理不会将对象存储到任何持久化存储中。请注意，此缓存功能旨在实现免维护运行，仅专注于节省 HAProxy 的宝贵资源，而非节省服务器资源。旨在优化服务器的缓存需要更多的调优和灵活性。如需此类高级缓存功能，请使用 Varnish Cache，其与 HAProxy 集成良好，尤其在任一侧需要 SSL/TLS 时。

- FastCGI 网关：FastCGI 可被视为 HTTP 的另一种表现形式，因此 HAProxy 可直接对任意组合的 FastCGI 应用服务器集群进行负载均衡，无需在它们之间插入额外的网关层。这可节省资源并降低维护成本。

HAProxy 不是：

- 显式 HTTP 代理，即浏览器用于访问互联网的代理。此类任务已有诸多优秀的开源软件专门支持，例如 Squid。然而，可在此类代理前部署 HAProxy，以实现负载均衡和高可用性。

- 数据清理器：不会修改请求或响应的正文内容。

- 静态 Web 服务器：启动期间，它会将自身隔离在 chroot 环境中并放弃特权，因此启动后将不会执行任何文件系统访问操作。因此，它无法被用作静态 Web 服务器（动态服务器可通过 FastCGI 支持）。此类用途有众多优秀的开源软件可供选择，例如 Apache 或 NGINX，HAProxy 可轻松部署在它们前端，以提供负载均衡、高可用性和加速功能。

- 基于数据包的负载均衡器：它不会处理 IP 数据包或 UDP 数据报，也不会执行 NAT 或更不用说 DSR。这些任务应由更低层级完成。某些基于内核的组件（如 IPVS（Linux 虚拟服务器））已能很好地完成此类工作，并与 HAProxy 完美互补。

## 3.2. HAProxy 的工作原理 {#section-3-2}

HAProxy 是一个基于事件驱动、非阻塞的引擎，结合了极快的 I/O 层与基于优先级的多线程调度器。由于其设计目标是数据转发，架构经过优化，能够在最少的操作下尽可能快速地传输数据。它通过尽可能将连接绑定到同一 CPU 来提升 CPU 缓存的使用效率。因此，它采用分层模型，在每一层都提供绕行机制，确保数据仅在必要时才传递到更高层级。大部分处理工作在内核中完成，HAProxy 尽最大努力通过提供一些提示或在预判后续操作可合并时避免某些操作，来帮助内核尽可能高效地完成工作。结果表明，典型情况下，在 TCP 或 HTTP 关闭模式下，HAProxy 占用约 15% 的处理时间，内核占用 85%；在 HTTP 持久连接模式下，HAProxy 占用约 30%，内核占用 70%。

一个进程可以运行多个代理实例；有报告称单个进程中运行多达 300000 个不同代理实例也能正常工作。对于超过 99% 的用户而言，单核、单 CPU 的配置已完全足够，因此使用容器和虚拟机的用户应尽量采用最小的镜像，以降低运营成本并简化故障排查。然而，HAProxy 所运行的机器绝不能进行交换（swap），其 CPU 也不得被人为限速（如虚拟化环境中低于单 CPU 的分配），更不应与计算密集型进程共享，否则将导致极高的上下文切换延迟。

多线程机制可通过每个 CPU 核心使用一个线程的方式，充分利用所有可用的处理能力。该机制在处理 SSL 或需要超过 40 Gbps 的数据转发速率时尤为有用。在此类场景下，避免多个物理 CPU 之间的通信至关重要，否则可能导致网络栈及 HAProxy 本身出现严重瓶颈。尽管对部分用户而言看似反直觉，但在面对性能问题时，通常应优先考虑减少 HAProxy 所运行的 CPU 数量。

HAProxy 仅需 HAProxy 可执行文件和配置文件即可运行。为实现日志记录，强烈建议配置好 syslog 守护进程并设置日志轮转。日志也可发送至 stdout/stderr，这在容器环境中尤为有用。配置文件在启动前被解析，随后 HAProxy 会尝试绑定所有监听套接字，若任一绑定失败则拒绝启动。一旦越过此阶段，便不再可能失败。这意味着不存在运行时故障，若 HAProxy 确认启动，则将持续正常运行直至被停止。

HAProxy 启动后，将执行以下三项操作：

- 处理入站连接；

- 定期检查服务器状态（称为健康检查）；

- 与其他 HAProxy 节点交换信息。

处理传入连接是迄今为止最复杂的任务，因为它依赖于众多配置选项，但可以概括为以下 9 个步骤：

- 接受来自属于名为“前端”（frontend）的配置实体的监听套接字的入站连接，该前端引用一个或多个监听地址；

- 对这些连接应用前端特定的处理规则，可能造成连接被阻断、修改部分头信息，或拦截连接以执行某些内部小程序，例如统计页面或 CLI；

- 将这些传入连接转发至另一个代表服务器集群的配置实体，即“后端”，该后端包含服务器列表以及此服务器集群的负载均衡策略；

- 对这些连接应用后端特定的处理规则；

- 根据负载均衡策略决定将连接转发至哪台服务器；

- 对响应数据应用后端特定的处理规则；

- 对响应数据应用前端特定的处理规则；

- 发送日志以详细报告发生的情况；

- 在 HTTP 中，返回第二步以等待新请求；否则，关闭连接。

前端和后端有时被视为半代理，因为它们仅关注端到端连接的一侧；前端仅关注客户端，而后端仅关注服务器。HAProxy 还支持全代理，其定义为前端与后端的完全并集。当需要进行 HTTP 处理时，配置通常会划分为前端和后端，因为这种结构提供了大量灵活性，任意前端均可将连接转发至任意后端。在仅使用 TCP 的代理场景中，使用前端和后端通常无法带来明显优势，采用全代理配置反而可能使配置更清晰易读。
