本文档不提供任何配置方面的帮助或提示,但它解释了在哪里可以找到相关文档。下面的概述旨在帮助您按名称搜索章节并在文档中导航。致文档贡献者:本文档的格式为每行 80 列,缩进使用偶数个空格,不使用制表符。请严格遵守这些规则,以便在任何地方都能轻松打印。如果您添加章节,请更新下面的概述以便于搜索。
| 1. | 可用文档 | |
2. |
负载均衡和负载均衡器的快速入门 | |
3. |
HAProxy 简介 | |
| 3.1. | ||
| 3.2. | ||
| 3.3. | ||
| 3.3.1. | ||
| 3.3.2. | ||
| 3.3.3. | ||
| 3.3.4. | ||
| 3.3.5. | ||
| 3.3.6. | ||
| 3.3.7. | ||
| 3.3.8. | ||
| 3.4. | ||
| 3.4.1. | ||
| 3.4.2. | ||
| 3.4.3. | ||
| 3.4.4. | ||
| 3.4.5. | ||
| 3.4.6. | ||
| 3.4.7. | ||
| 3.4.8. | ||
| 3.5. | ||
| 3.5.1. | ||
| 3.5.2. | ||
| 3.5.3. | ||
| 3.5.4. | ||
| 3.6. | ||
| 3.7. | ||
4. |
配套产品和替代方案 | |
| 4.1. | ||
| 4.2. | ||
| 4.3. | ||
| 4.4. | ||
5. |
联系方式 |
HAProxy 的完整文档包含在以下文件中。请务必查阅相关文档,以节省时间并获得最准确的响应。也请不要向邮件列表发送文档中已有答案的问题。 - intro.txt(本文档):介绍了负载均衡的基础知识、HAProxy 作为产品的功能、不适用的场景、一些已知的陷阱、特定于操作系统的限制、如何获取、如何演进、如何确保运行所有已知修复、如何更新、补充和替代方案。 - management.txt:解释了如何启动 haproxy、如何在运行时管理它、如何在多个节点上管理它以及如何进行无缝升级。 - configuration.txt:参考手册详细介绍了所有配置关键字及其选项。在需要更改配置时使用。 - coding-style.txt:这是为希望为项目贡献代码的开发人员准备的。它解释了应采用的代码风格。它不是很严格,并非所有代码库都完全遵守它,但与它偏差太大的贡献将被拒绝。 - proxy-protocol.txt:这是 PROXY 协议的事实标准规范,HAProxy 和许多第三方产品都实现了该协议。 - README:如何从源代码构建 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、主机标头字段、URL 或其他信息,负载均衡器可能需要解密 SSL/TLS 流量,甚至可能在将其传递给服务器时重新加密。这项昂贵的任务解释了为什么在某些高流量基础设施中,有时可能有很多负载均衡器。由于第7层负载均衡器可以对流量执行许多复杂的操作(解密、解析、修改、匹配 cookie、决定发送到哪个服务器等),它肯定会引起一些麻烦,并且通常会被指责为它所揭示的许多麻烦的罪魁祸首。通常会发现服务器不稳定并周期性地上下线,或者对于 Web 服务器,它们提供的页面带有硬编码链接,迫使客户端直接连接到一个特定的服务器,而无需通过负载均衡器,或者它们在高负载下响应缓慢导致超时。这就是为什么日志记录是第7层负载均衡的一个极其重要的方面。一旦报告了问题,重要的是要弄清楚负载均衡器是否做出了错误的决定,如果是,为什么会发生,以便不再发生。
HAProxy 写成“HAProxy”以指代产品,写成“haproxy”以指代可执行程序、软件包或进程。然而,两者通常都用于这两个目的,并且读作 H-A-Proxy。很早以前,“haproxy”代表“high availability proxy”,并且这个名字被写成两个独立的单词,尽管现在它只代表“HAProxy”。
HAProxy 是: - TCP 代理:它可以接受来自监听套接字的 TCP 连接,连接到服务器并将这些套接字连接在一起,允许流量在两个方向上流动;支持 IPv4、IPv6 甚至 UNIX 套接字,因此这可以提供一种在不同系列之间转换地址的简单方法。 - HTTP 反向代理(在 HTTP 术语中称为“网关”):它将自己呈现为服务器,通过在监听 TCP 套接字上接受的连接接收 HTTP 请求,并将这些连接中的请求使用不同的连接传递给服务器。它可以在任何一侧使用 HTTP/1.x 或 HTTP/2 的任意组合,并且在使用 TLS 上的 ALPN 时甚至会自动检测每侧使用的协议。 - SSL 终止器/发起器/卸载器:SSL/TLS 可用于来自客户端的连接、用于发送到服务器的连接,甚至用于两个连接。许多设置可以按名称(SNI)应用,并且可以在运行时更新而无需重新启动。此类设置具有极强的可扩展性,据报道涉及数万到数十万证书的部署。 - TCP 规范化器:由于连接由操作系统本地终止,因此两侧之间没有关系,因此异常流量,例如无效数据包、标志组合、窗口通告、序列号、不完整连接(SYN 洪水)等,将不会传递到另一侧。这保护了脆弱的 TCP 堆栈免受协议攻击,并且还允许优化与客户端的连接参数,而无需修改服务器的 TCP 堆栈设置。 - HTTP 规范化器:当配置为处理 HTTP 流量时,只传递有效的完整请求。这可以防止许多基于协议的攻击。此外,规范中允许的协议偏差会得到修复,以便它们不会在服务器上引起问题(例如,多行标头)。 - HTTP 修复工具:它可以修改/修复/添加/删除/重写 URL 或任何请求或响应标头。这有助于修复复杂环境中的互操作性问题。 - 基于内容的交换机:它可以考虑请求中的任何元素来决定将请求或连接传递给哪个服务器。因此,可以在同一端口上处理多种协议(例如 HTTP、HTTPS、SSH)。 - 服务器负载均衡器:它可以对 TCP 连接和 HTTP 请求进行负载均衡。在 TCP 模式下,负载均衡决策针对整个连接进行。在 HTTP 模式下,决策针对每个请求进行。 - 流量调节器:它可以在各个点应用一些速率限制,保护服务器免受过载,根据内容调整流量优先级,甚至通过标记数据包将此类信息传递给较低层和外部网络组件。 - 针对 DDoS 和服务滥用的保护:它可以维护每个 IP 地址、URL、cookie 等的大量统计信息,并检测何时发生滥用,然后采取行动(减慢攻击者、阻止他们、将他们发送到过时内容等)。 - 用于网络故障排除的观察点:由于日志中报告的信息精确度高,它通常用于缩小一些网络相关问题的范围。 - HTTP 压缩卸载器:它可以压缩未被服务器压缩的响应,从而减少连接不良或使用高延迟移动网络的客户端的页面加载时间。 - 缓存代理:它可以将响应缓存在 RAM 中,以便对同一对象的后续请求避免从服务器进行另一次网络传输的成本,只要该对象保持存在且有效。然而,它不会将对象存储到任何持久存储中。请注意,此缓存功能设计为免维护,并且仅专注于节省 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 完美互补。
HAProxy 是一个事件驱动、非阻塞引擎,结合了非常快的 I/O 层和基于优先级的多线程调度程序。由于其设计目标是数据转发,因此其架构经过优化,可以以最少的操作尽快移动数据。它专注于通过尽可能长时间地将连接保持在同一 CPU 上来优化 CPU 缓存效率。因此,它实现了一个分层模型,在每个级别提供绕过机制,确保数据除非需要,否则不会到达更高层级。大部分处理在内核中执行,HAProxy 尽力通过提供一些提示或避免某些操作(当它猜测它们可以在以后分组时)来帮助内核尽快完成工作。因此,典型的数字显示,在 TCP 或 HTTP 关闭模式下,HAProxy 占用的处理时间为 15%,而内核占 85%;在 HTTP keep-alive 模式下,HAProxy 占 30%,而内核占 70%。单个进程可以运行许多代理实例;据报道,单个进程中多达 300000 个不同代理的配置运行良好。对于超过 99% 的用户来说,单个核心、单个 CPU 设置绰绰有余,因此,鼓励容器和虚拟机用户使用他们能获得的绝对最小镜像,以节省运营成本并简化故障排除。然而,HAProxy 运行的机器绝不能交换,其 CPU 也不能被人为限制(超管理器中的子 CPU 分配),也不能与计算密集型进程共享,因为这会导致非常高的上下文切换延迟。线程允许通过为每个 CPU 核心使用一个线程来利用所有可用的处理能力。这主要用于 SSL 或需要超过 40 Gbps 数据转发速率的情况。在这种情况下,避免多个物理 CPU 之间的通信至关重要,因为这可能会在网络堆栈和 HAProxy 本身中造成严重的瓶颈。尽管这对于某些人来说是违反直觉的,但在面临性能问题时,首先要做的往往是减少 HAProxy 运行的 CPU 数量。HAProxy 只需要 haproxy 可执行文件和配置文件即可运行。对于日志记录,强烈建议配置适当的 syslog 守护程序和日志轮换。日志也可以发送到 stdout/stderr,这在容器内部很有用。配置文件在启动前解析,然后 HAProxy 尝试绑定所有监听套接字,如果任何操作失败,则拒绝启动。过了这一点,它就不会再失败了。这意味着没有运行时故障,如果它接受启动,它将一直工作直到停止。HAProxy 启动后,它只做 3 件事: - 处理传入连接; - 定期检查服务器状态(称为健康检查); - 与其他 haproxy 节点交换信息。处理传入连接是迄今为止最复杂的任务,因为它依赖于许多配置可能性,但可以总结为以下 9 个步骤: - 接受来自属于称为“前端”的配置实体的监听套接字的传入连接,该实体引用一个或多个监听地址; - 对这些连接应用前端特定的处理规则,这可能导致阻止它们、修改某些标头或拦截它们以执行一些内部小程序(例如统计信息页面或 CLI); - 将这些传入连接传递给代表服务器集群的另一个配置实体,称为“后端”,其中包含服务器列表和该服务器集群的负载均衡策略; - 对这些连接应用后端特定的处理规则; - 根据负载均衡策略决定将连接转发到哪个服务器; - 对响应数据应用后端特定的处理规则; - 对响应数据应用前端特定的处理规则; - 发出日志以详细报告发生的情况; - 在 HTTP 中,循环回到第二步以等待新请求,否则关闭连接。前端和后端有时被视为半代理,因为它们只关注端到端连接的一侧;前端只关心客户端,而后端只关心服务器。HAProxy 还支持全代理,全代理恰好是前端和后端的结合。当需要 HTTP 处理时,配置通常会分为前端和后端,因为它们提供了很多可能性,任何前端都可以将连接传递给任何后端。对于纯 TCP 代理,使用前端和后端很少提供好处,并且使用全代理的配置可能更具可读性。
本节将列举 HAProxy 实现的许多功能,其中一些是任何现代负载均衡器通常期望的,而另一些则是 HAProxy 架构的直接优势。更高级的功能将在下一节中详细介绍。
代理是将数据在客户端和服务器之间通过两个独立连接传输的操作。HAProxy 支持以下有关代理和连接管理的基本功能: - 为服务器提供干净的连接,以保护它们免受任何客户端缺陷或攻击; - 监听多个 IP 地址和/或端口,甚至是端口范围; - 透明接受:拦截针对不属于本地系统的任意 IP 地址的流量; - 服务器端口不需要与监听端口相关联,甚至可以通过固定偏移量进行转换(在范围中很有用); - 透明连接:如果需要,在连接到服务器时欺骗客户端(或任何)IP 地址; - 在多站点负载均衡器中为服务器提供可靠的返回 IP 地址; - 通过缓冲区和可能的短连接卸载服务器,以减少其并发连接数和内存占用; - 优化 TCP 堆栈(例如 SACK)、拥塞控制,并减少 RTT 影响; - 支持两侧不同的协议族(例如 IPv4/IPv6/Unix); - 超时强制执行:HAProxy 支持多个级别的超时,具体取决于连接所处的阶段,因此死掉的客户端或服务器或攻击者不能占用资源太久; - 协议验证:检查 HTTP、SSL 或有效负载,并拒绝无效的协议元素,除非指示无论如何都接受它们; - 策略强制执行:确保只转发允许的内容; - 传入和传出连接都可以限制在特定的网络命名空间(仅限 Linux),从而轻松构建跨容器、多租户负载均衡器; - PROXY 协议将客户端的 IP 地址呈现给服务器,即使是非 HTTP 流量也是如此。这是 HAProxy 的扩展,迄今为止已被许多第三方产品采用,至少在撰写本文时有这些产品: - 客户端:haproxy、stud、stunnel、exaproxy、ELB、squid - 服务器:haproxy、stud、postfix、exim、nginx、squid、node.js、varnish
根据 Google 工程师的说法,HAProxy 的 SSL 堆栈被公认为功能最丰富的之一(http://istlsfastyet.com/)。使其相当完整的最常用功能是: - 基于 SNI 的多主机托管,对站点数量没有限制,并专注于性能。至少有一个部署已知运行着 50000 个域及其各自的证书; - 支持通配符证书减少了对许多证书的需求; - 基于证书的客户端身份验证,对未能提供有效证书的策略可配置。这允许呈现不同的服务器集群来重新生成客户端证书等; - 后端服务器的身份验证确保后端服务器是真实的,而不是中间人; - 与后端服务器的身份验证让后端服务器知道连接到它的是预期的 haproxy 节点; - TLS NPN 和 ALPN 扩展使得可靠地卸载 SPDY/HTTP2 连接并以明文形式将其传递给后端服务器成为可能; - OCSP stapling 通过在客户端请求证书状态请求时提供内联 OCSP 响应,进一步减少了首次页面加载时间; - 动态记录大小提供了高性能和低延迟,并通过让浏览器在数据包仍在传输中时开始获取新对象,显著减少了页面加载时间; - 永久访问所有相关的 SSL/TLS 层信息,用于日志记录、访问控制、报告等。这些元素可以嵌入到 HTTP 标头中,甚至作为 PROXY 协议扩展,以便卸载的服务器获得它自己执行 SSL 终止时会获得的所有信息。 - 检测、记录和阻止某些已知攻击,即使是在易受攻击的 SSL 库上,例如影响某些 OpenSSL 版本的 Heartbleed 攻击。 - 支持无状态会话恢复(RFC 5077 TLS Ticket 扩展)。TLS 票证可以从 CLI 更新,这为它们提供了通过频繁轮换票证来实现完美前向保密的方法。
HAProxy 非常注重可用性。因此,它关心服务器状态,并关心向其他网络组件报告自身状态: - 使用每个服务器参数持续监控服务器状态。这确保了服务器的路径对于常规流量是可操作的; - 健康检查支持上下转换的两种滞后,以防止状态抖动; - 检查可以发送到不同的地址/端口/协议:这使得检查被认为是多个服务的代表的单个服务变得容易,例如 HTTP+HTTPS 服务器的 HTTPS 端口。 - 服务器可以跟踪其他服务器并同时宕机:这确保了托管多个服务的服务器可以原子地失败,并且没有人会被发送到部分失败的服务器; - 可以在服务器上部署代理来监控负载和健康状况:服务器可能有兴趣报告其负载、操作状态、管理状态,独立于健康检查所能看到的内容。通过在服务器上运行一个简单的代理,除了验证整个路径的健康检查之外,还可以考虑服务器对其自身健康状况的看法; - 提供各种检查方法:TCP 连接、HTTP 请求、SMTP hello、SSL hello、LDAP、SQL、Redis、发送/期望脚本,所有这些都带/不带 SSL; - 状态更改会在日志和统计信息页面中报告,并带有故障原因(例如在检测到故障时收到的 HTTP 响应)。在发生此类更改时,还可以向可配置的地址发送电子邮件; - 服务器状态也会在统计信息界面上报告,可用于制定路由决策,以便根据其大小和/或健康状况将流量发送到不同的集群(例如,城际链路丢失); - HAProxy 可以使用健康检查请求将信息传递给服务器,例如它们的名称、权重、集群中其他服务器的数量等,以便服务器可以根据这些知识调整其响应和决策(例如,推迟备份以保持更多 CPU 可用); - 服务器可以使用健康检查报告比仅开/关更详细的状态(例如,我想停止,请停止发送新访问者); - HAProxy 本身可以向外部组件(例如路由器或其他负载均衡器)报告其状态,从而允许构建非常完整的多路径和多层基础设施。
就像任何严肃的负载均衡器一样,HAProxy 非常关心可用性,以确保最佳的全局服务连续性: - 仅使用有效的服务器;其他服务器会自动从负载均衡集群中驱逐;在某些条件下,仍然可以强制使用它们; - 支持优雅关机,以便在不影响任何连接的情况下将服务器从集群中移除; - 当活动服务器宕机时,备份服务器会自动使用并替换它们,以便在可能的情况下不会丢失会话。这也允许构建到达同一服务器的多条路径(例如,多个接口); - 当太多服务器宕机时,能够返回集群的全局失败状态。这与监控功能相结合,使得上游组件可以选择给定服务的不同负载均衡节点; - 无状态设计使得构建集群变得容易:通过设计,HAProxy 尽力确保最高的服务连续性,而无需存储可能在发生故障时丢失的信息。这确保了接管尽可能无缝; - 与标准 VRRP 守护程序 keepalived 良好集成:HAProxy 轻松告诉 keepalived 它的状态,并且与浮动虚拟 IP 地址配合得很好。注意:仅在集群解决方案(Heartbeat...)上使用 IP 冗余协议(VRRP/CARP),因为它们提供了最快、最无缝和最可靠的切换。
HAProxy 提供了一套相当完整的负载均衡功能,其中大部分在许多其他负载均衡产品中都没有: - 支持不少于 10 种负载均衡算法,其中一些适用于输入数据以提供无限的可能性列表。最常见的包括循环(对于短连接,依次选择每个服务器)、最少连接(对于长连接,选择连接数最少的服务器中最近最少使用的服务器)、源地址(对于 SSL 集群或终端服务器集群,服务器直接取决于客户端的源地址)、URI(对于 HTTP 缓存,服务器直接取决于 HTTP URI)、hdr(服务器直接取决于特定 HTTP 标头字段的内容)、first(对于短命虚拟机,所有连接都打包在尽可能小的服务器子集上,以便未使用的服务器可以关闭电源); - 上述所有算法都支持每个服务器的权重,因此可以容纳集群中的不同服务器代,或将一小部分流量导向特定服务器(调试模式、运行下一个版本的软件等); - 循环、最少连接和一致性哈希支持动态权重;这允许从 CLI 甚至在服务器上运行的代理动态修改服务器权重; - 只要支持动态权重,就支持慢启动;这允许服务器逐步接收流量。这对于需要运行时编译类以及需要填充缓存才能全速运行的冷缓存的脆弱应用程序服务器来说是一个重要功能; - 哈希可以应用于各种元素,例如客户端的源地址、URL 组件、查询字符串元素、标头字段值、POST 参数、RDP cookie; - 一致性哈希保护服务器集群在添加或删除服务器时免受大规模重新分配。这在大型缓存集群中非常重要,它允许使用慢启动来重新填充冷缓存; - 许多内部指标,例如每个服务器、每个后端的连接数、后端中可用连接槽的数量等,使得构建非常高级的负载均衡策略成为可能。
如果没有粘性,应用程序负载均衡将毫无用处。HAProxy 提供了一套相当全面的可能性,即使在各种事件(例如服务器添加/移除、宕机/恢复周期)中也能将访问者保持在同一服务器上,并且某些方法旨在抵抗多个负载均衡节点之间的距离,因为它们不需要任何复制: - 如果需要,可以从不同的位置单独匹配和学习粘性信息。例如,JSESSIONID cookie 可以在 cookie 和 URL 中同时匹配。最多可以同时学习 8 个并行源,每个源可能指向不同的 stick-table; - 粘性信息可以来自请求或响应中可见的任何内容,包括源地址、TCP 有效负载偏移量和长度、HTTP 查询字符串元素、标头字段值、cookie 等。 - stick-table 以多主模式在所有节点之间复制; - 常用元素(例如 SSL-ID 或 RDP cookie(用于 TSE 集群))可直接访问,以方便操作; - 所有粘性规则都可以通过 ACL 进行动态条件限制; - 可以决定不粘在某些服务器上,例如备份服务器,以便当标称服务器恢复时,它会自动重新接管负载。这通常用于多路径环境; - 在 HTTP 中,通常最好不学习任何东西,而是操作专用于粘性的 cookie。为此,可以检测、重写、插入或为此类 cookie 添加前缀,以让客户端记住分配给它的服务器; - 服务器可以决定在注销时更改或清除粘性 cookie,以便离开的访问者自动与服务器解绑; - 使用基于 ACL 的规则,还可以选择性地忽略或强制执行粘性,无论服务器状态如何;结合高级健康检查,这有助于管理员在向全世界展示服务器之前验证他们正在安装的服务器是否已启动并运行; - 一种创新的机制,用于设置 cookie 的最大空闲时间和持续时间,确保在永不关闭的设备(智能手机、电视、家用电器)上可以平稳地停止粘性,而无需将它们存储在持久存储中; - 多个服务器条目可以共享相同的粘性密钥,以便在多路径环境中当一条路径宕机时不会丢失粘性; - 软停止确保只有具有粘性信息的用户才会继续访问分配给他们的服务器,但不会有新用户去那里。
日志记录对于负载均衡器来说是一个极其重要的功能,首先是因为负载均衡器通常被错误地指责为引起它所揭示的问题,其次是因为它位于基础设施中的关键点,需要分析所有正常和异常活动并与其他组件关联。HAProxy 提供非常详细的日志,具有毫秒级精度和确切的连接接受时间,可以在防火墙日志中搜索(例如,用于 NAT 关联)。默认情况下,TCP 和 HTTP 日志非常详细,包含故障排除所需的一切,例如源 IP 地址和端口、前端、后端、服务器、计时器(请求接收持续时间、队列持续时间、连接设置时间、响应标头时间、数据传输时间)、全局进程状态、连接计数、队列状态、重试计数、详细的粘性操作和断开连接原因、带有安全输出编码的标头捕获。然后可以扩展或替换此格式以包含任何采样数据、变量、捕获,从而产生非常详细的信息。例如,可以记录客户端访问的累积请求数或不同 URL 数。可以使用标准 ACL 按请求调整日志级别,因此可以自动静默被视为干扰的某些日志,并在小部分流量发生异常行为时发出警告(例如,源地址的 URL 或 HTTP 错误过多)。管理日志也会发出自己的级别,以告知例如服务器丢失或恢复。每个前端和后端可以使用多个独立的日志输出,这简化了多租户。日志最好通过 UDP 发送,可能采用 JSON 编码,并在可配置的行长度后截断,以保证交付。但也可以将它们发送到 stdout/stderr 或任何文件描述符,以及发送到客户端可以订阅以检索它们的环形缓冲区。
HAProxy 提供一个基于 Web 的统计信息报告界面,具有身份验证、安全级别和范围。因此,可以为每个托管的客户提供他们自己的页面,只显示他们自己的实例。此页面可以位于常规网站的隐藏 URL 部分,这样就不需要打开新端口。此页面还可以报告其他 HAProxy 节点的可用性,以便一目了然地发现一切是否按预期工作。视图是综合性的,并且有很多详细信息可供访问(例如,错误原因、最后访问时间和最后更改时长等),这些信息也可作为 CSV 表格提供,其他工具可以导入该表格来绘制图表。页面可以自我刷新,以便在大显示器上用作监控页面。在管理模式下,该页面还允许更改服务器状态以简化维护操作。还提供了一个 Prometheus 导出器,以便统计信息可以根据部署以不同的格式进行消耗。
在本节中,列举了一些在 HAProxy 中非常常用但并非在其他负载均衡器上普遍存在的功能。
HAProxy 支持使用广泛的“样本获取函数”进行信息采样。原理是提取称为样本的信息片段,供立即使用。这用于粘性、构建条件、在日志中生成信息或丰富 HTTP 标头。可以从各种来源获取样本: - 常量:整数、字符串、IP 地址、二进制块; - 进程:日期、环境变量、服务器/前端/后端/进程状态、字节/连接计数/速率、队列长度、随机生成器... - 变量:每个会话、每个请求、每个响应变量; - 客户端连接:源和目标地址和端口,以及所有相关的统计计数器; - SSL 客户端会话:协议、版本、算法、密码、密钥大小、会话 ID、所有客户端和服务器证书字段、证书序列、SNI、ALPN、NPN、客户端对某些扩展的支持; - 请求和响应缓冲区内容:偏移量/长度处的任意有效负载、数据长度、RDP cookie、SSL hello 类型的解码、TLS SNI 的解码; - HTTP(请求和响应):方法、URI、路径、查询字符串参数、状态代码、标头值、位置标头值、cookie、捕获、身份验证、正文元素;然后样本可以通过许多称为“转换器”的操作符进行一些转换。转换器消耗一个样本并产生一个新的样本,可能是一种完全不同的类型。例如,转换器可用于仅返回输入字符串的整数长度,或者可以将字符串转换为大写。在最终使用之前,可以对样本应用任意数量的转换器。在所有可用的样本转换器中,以下是使用最常见的: - 算术和逻辑运算符:它们使得对输入数据执行高级计算成为可能,例如计算比率、百分比或简单地从一个单位转换为另一个单位; - IP 地址掩码在需要按更大网络对某些地址进行分组时很有用; - 数据表示:URL 解码、base64、十六进制、JSON 字符串、哈希; - 字符串转换:提取固定位置、固定长度的子字符串、提取特定分隔符周围的特定字段、提取特定单词、更改大小写、应用基于正则表达式的替换; - 日期转换:转换为 HTTP 日期格式、本地转换为 UTC 反之亦然、添加或删除偏移量; - 在 stick table 中查找条目以查找统计信息或分配的服务器; - 从文件进行基于映射的键到值转换(主要用于地理定位)。
映射是一种强大的转换器类型,它通过在启动时将一个两列文件加载到内存中,然后从第一列查找每个输入样本,如果找到条目,则返回第二列中的相应模式,否则返回默认值。输出信息也是一个样本,它可以经历其他转换,包括其他映射查找。映射最常用于将客户端的 IP 地址转换为 AS 号或国家代码,因为它们支持网络地址的最长匹配,但它们可以用于各种其他目的。它们的部分优势在于它们可以从 CLI 或通过其他样本的某些操作进行动态更新,从而使它们能够存储和检索后续访问之间的信息。另一个优势来自基于二进制树的索引,这使得它们即使包含数十万个条目也极其快速,从而使地理位置的设置非常便宜且容易。
HAProxy 中的大多数操作都可以是有条件的。条件是通过使用逻辑运算符(AND、OR、NOT)组合多个 ACL 来构建的。每个 ACL 都是一系列基于以下元素的测试: - 用于检索要测试元素的样本获取方法; - 可选的一系列转换器来转换元素; - 要匹配的模式列表; - 用于指示如何将模式与样本进行比较的匹配方法。例如,样本可以取自 HTTP“Host”标头,然后可以将其转换为小写,然后使用正则表达式匹配方法与许多正则表达式模式匹配。从技术上讲,ACL 是在与映射相同的核心上构建的,它们共享完全相同的内部结构、模式匹配方法和性能。唯一的真正区别是,它们不是返回样本,而是只返回“找到”或“未找到”。在使用方面,ACL 模式可以在配置文件中声明,不需要自己的文件。ACL 可以命名以便于使用或使配置易于理解。命名 ACL 可以多次声明,它将依次评估所有定义,直到其中一个匹配为止。提供了大约 13 种不同的模式匹配方法,其中包括 IP 地址掩码、整数范围、子字符串、正则表达式。它们像函数一样工作,就像任何编程语言一样,只评估需要评估的内容,因此当涉及 OR 的条件已经为真时,接下来的条件不会被评估,同样当涉及 AND 的条件已经为假时,条件的其余部分也不会被评估。声明的 ACL 数量没有实际限制,并提供了一些常用的 ACL。然而,经验表明,使用大量命名 ACL 的设置很难排除故障,有时使用匿名 ACL 内联更容易,因为它需要的分析范围之外的引用较少。
HAProxy 实现了一种称为基于内容的交换机制。原理是连接或请求到达前端,然后处理此请求或连接携带的信息,此时可以编写使用这些信息来决定哪个后端将处理请求的基于 ACL 的条件。因此,根据请求的内容将流量导向一个后端或另一个后端。最常见的示例是使用 Host 标头和/或路径中的元素(子目录或文件扩展名)来决定 HTTP 请求是针对静态对象还是应用程序,并将静态对象流量路由到由快速轻量级服务器组成的后端,而所有剩余流量路由到更复杂的应用程序服务器,从而构成细粒度的虚拟主机解决方案。这对于使多种技术共存作为更全局的解决方案非常方便。内容交换的另一个用例是根据各种标准使用不同的负载均衡算法。缓存可以使用 URI 哈希,而应用程序可以使用循环。最后但同样重要的是,它允许多个客户通过强制执行每个后端(从而每个客户连接限制)来使用公共资源的一小部分份额。内容交换规则扩展性很好,尽管它们的性能可能取决于使用的 ACL 数量和复杂性。但也可以编写动态内容交换规则,其中样本值直接转换为后端名称,根本不使用 ACL。据报道,此类配置在生产环境中至少有 300000 个后端运行良好。
Stick-table 通常用于存储粘性信息,即保留对特定访问者被导向的服务器的引用。密钥是与访问者关联的标识符(其源地址、连接的 SSL ID、HTTP 或 RDP cookie、从 URL 或有效负载中提取的客户编号等),存储的值是服务器的标识符。Stick table 可以使用 3 种不同类型的样本作为其密钥:整数、字符串和地址。在代理中只能引用一个 stick-table,并且它在任何地方都用代理名称指定。最多可以并行跟踪 8 个密钥。一旦密钥和服务器都已知,服务器标识符将在请求或响应处理期间提交。Stick-table 内容可以以主-主模式复制到称为“对等体”的其他 HAProxy 节点,以及在重新加载操作期间复制到新进程,以便所有负载均衡节点共享相同的信息,并在客户端请求分散到多个节点时做出相同的路由决策。由于 stick-table 是根据允许识别客户端的内容进行索引的,因此它们通常也用于存储额外信息,例如每个客户端的统计信息。额外的统计信息会占用一些额外的空间,需要明确声明。可以存储的统计信息类型包括输入和输出带宽、并发连接数、一段时间内的连接速率和计数、错误数量和频率、一些特定的标签和计数器等。为了支持保留此类信息而不必强制粘在给定服务器上,实现了一个特殊的“跟踪”功能,允许同时跟踪来自不同表的最多 3 个密钥,无论粘性规则如何。每个存储的统计信息都可以从 CLI 搜索、转储和清除,并增加了实时故障排除功能。虽然此机制可用于为返回的访问者提供特权或根据良好或不良行为调整提供的服务质量,但它主要用于对抗服务滥用和更普遍的 DDoS,因为它允许构建复杂的模型以高处理速度检测某些不良行为。
HAProxy 需要在许多地方处理字符串,例如日志、重定向、标头添加等。为了提供最大的灵活性,引入了“格式化字符串”的概念,最初是为了日志记录目的,因此它仍然被称为“log-format”。这些字符串包含转义字符,允许将各种动态数据(包括变量和样本获取表达式)引入字符串,甚至在结果被转换为字符串时调整编码(例如,添加引号)。这提供了一种强大的方法来构建标头内容、响应数据甚至响应模板,或自定义日志行。此外,为了保持大多数常见字符串的构建简单,提供了大约 50 个特殊标签作为日志中常用信息的快捷方式。
在从未为此设计的应用程序前面安装负载均衡器,如果没有适当的工具,可能是一项具有挑战性的任务。在这种情况下,最常请求的操作之一是调整请求和响应标头,使负载均衡器显示为源服务器并修复硬编码信息。这涉及到更改请求中的路径(强烈不建议这样做)、修改 Host 标头字段、修改重定向的 Location 响应标头字段、修改 cookie 的路径和域属性等。还存在一些服务器在响应中过于冗长并倾向于泄漏过多信息的情况,使它们更容易受到有针对性的攻击。虽然从理论上讲,这不是负载均衡器的职责,但在实践中,它位于基础设施中最好的位置来保证一切都得到清理。同样,有时负载均衡器需要拦截一些请求并重定向到新的目标 URL。虽然有些人倾向于混淆重定向和重写,但这是两个完全不同的概念,因为重写使客户端和服务器看到不同的东西(并且在访问页面的位置上存在分歧),而重定向要求客户端访问新的 URL,以便它看到与服务器相同的位置。为了做到这一点,HAProxy 支持各种重写和重定向的可能性,其中包括: - 请求和响应中基于正则表达式的 URL 和标头重写。正则表达式是最常用于修改标头值的工具,因为它们易于操作且易于理解; - 标头也可以根据格式化的字符串进行附加、删除或替换,以便可以将信息传递到那里(例如,客户端 TLS 算法和密码); - HTTP 重定向可以使用任何 3xx 代码到相对、绝对或完全动态(格式化字符串)URI; - HTTP 重定向还支持一些额外的选项,例如设置或清除特定 cookie、删除查询字符串、如果缺少则附加斜杠等; - 强大的“return”指令允许使用动态内容甚至模板文件自定义响应的每个部分,例如状态、标头、正文。 - 所有操作都支持基于 ACL 的条件;
HAProxy 做了很多工作来最大限度地提高服务可用性,为此它付出了巨大的努力来保护服务器免受过载和攻击。第一点也是最重要的一点是,只有完整且有效的请求才会被转发到服务器。最初的原因是 HAProxy 需要找到它需要与字节流保持同步的协议元素,第二个原因是直到请求完成,无法知道是否有元素会改变其语义。直接的好处是服务器不会暴露给无效或不完整的请求。这是针对 slowloris 攻击的非常有效的保护,它对 HAProxy 几乎没有影响。另一个重要点是 HAProxy 包含用于存储请求和响应的缓冲区,并且通过仅在请求完成后才将其发送到服务器,并通过从本地网络非常快速地读取整个响应,服务器端连接的使用时间非常短,这最大限度地保护了服务器资源。对此的直接扩展是 HAProxy 可以人为地限制服务器的并发连接数或未完成请求数,这保证了服务器即使在流量高峰期间持续以 100% 的容量运行也不会过载。所有多余的请求都将简单地排队,以便在一个槽位释放时进行处理。最终,这种巨大的资源节省通常确保了更好的服务器响应时间,以至于它最终实际上比使服务器过载更快。排队的请求可以重新分派到其他服务器,甚至在客户端中止时在队列中中止,这也保护了服务器免受“重新加载效应”的影响,即访问者在缓慢加载的页面上每次点击“重新加载”通常会引发新请求并使服务器保持过载状态。慢启动机制还保护重新启动的服务器免受高流量水平的影响,而它们仍在完成启动或编译某些类。关于协议级保护,可以放宽 HTTP 解析器以接受不符合标准但无害的请求或响应,甚至可以修复它们。这允许在开发修复程序时可以访问有问题的应用程序。同时,违规消息会被完全捕获,并附带详细报告,帮助开发人员发现应用程序中的问题。最危险的协议违规会被正确检测、处理和修复。例如,带有两个 Content-length 标头的格式错误请求或响应,如果值完全相同,则会修复;如果它们不同,则会拒绝,因为它会成为安全问题。协议检查不限于 HTTP,它也适用于其他协议,例如 TLS 或 RDP。当检测到协议违规或攻击时,有各种选项可以响应用户,例如返回常见的“HTTP 400 bad request”、使用 TCP 重置关闭连接,或者在长时间延迟后伪造错误(“tarpit”)以迷惑攻击者。所有这些都有助于通过阻止违规客户端继续进行维护成本高昂的攻击来保护服务器。HAProxy 还提出了一些更高级的选项来防止意外数据泄漏和会话交叉。它不仅可以记录可疑的服务器响应,还可以记录并选择性地阻止可能影响给定访问者机密性的响应。一个这样的例子是可缓存响应中出现的缓存 cookie,它可能导致中间缓存将其传递给另一个访问者,从而导致意外的会话共享。
HAProxy 旨在在常规生产环境中保持极其稳定和安全地管理。它以单个可执行文件提供,不需要任何安装过程。多个版本可以轻松共存,这意味着可以(并且建议)按重要性顺序逐步升级实例,而不是一次迁移所有实例。配置文件易于版本控制。配置检查是离线完成的,因此不需要重新启动可能会失败的服务。在配置检查期间,可能会检测到许多高级错误(例如,一条规则隐藏了另一条规则,或者粘性将不起作用),并提出了详细的警告和配置提示来修复它们。向后配置文件兼容性追溯到很久以前,版本 1.5 仍然完全支持 13 年前编写的 1.1 版本的配置,而 1.6 仅放弃了对几乎未使用、过时的关键字的支持,这些关键字可以用不同的方式完成。配置和软件升级机制是平稳且不中断的,因为它允许旧进程和新进程在系统上共存,每个进程处理自己的连接。系统状态、构建选项和库兼容性在启动时报告。一些高级功能允许应用程序管理员平稳地停止服务器,检测何时不再有活动,然后将其离线,停止它,升级它并确保它在升级期间不接收任何流量,然后通过正常路径再次测试它,而无需向公众开放,所有这些都无需触及 HAProxy。这确保了即使复杂的生产操作也可以在开放时间内完成,所有技术资源都可用。该进程尽量节省资源,使用内存池来节省分配时间并限制内存碎片,一旦发送其内容就释放有效负载缓冲区,并支持强制执行严格的内存限制,超过此限制时连接必须等待缓冲区可用,而不是分配更多内存。该系统有助于保证在某些严格环境中的内存使用。命令行界面(CLI)作为 UNIX 或 TCP 套接字提供,用于执行许多操作和检索故障排除信息。在此套接字上完成的所有操作都不需要更改配置,因此它主要用于临时更改。使用此界面,可以更改服务器的地址、权重和状态,查阅统计信息和清除计数器,转储和清除粘性表(可能按键标准选择性地清除),转储和终止客户端和服务器端连接,转储捕获的错误并详细分析错误的具体原因和位置,转储、添加和删除 ACL 和映射中的条目,更新 TLS 共享密钥,动态应用连接限制和速率限制到任意前端(在共享主机环境中很有用),并禁用特定前端以释放监听端口(在禁止白天操作但仍需要修复时很有用)。允许动态更新证书及其配置,以及启用和查阅流量的每个处理步骤的跟踪。对于强制使用 SNMP 的环境,至少存在两个代理,一个随 HAProxy 源代码提供,依赖于 Net-SNMP Perl 模块。另一个随商业软件包提供,不需要 Perl。两者在覆盖范围上大致相同。通常建议在部署 HAProxy 的机器上安装 4 个实用程序: - socat(用于连接到 CLI,尽管某些 netcat 分支也可以在一定程度上做到); - 来自最新 HAProxy 版本的 halog:这是日志分析工具,它可以极快地解析本机 TCP 和 HTTP 日志(每秒 1 到 2 GB),并提取有用的信息和统计信息,例如按 URL、按源地址的请求数、按响应时间或错误率排序的 URL、终止代码等。它旨在部署在生产服务器上以帮助解决实时问题,因此它必须在那里准备好使用; - tcpdump:强烈建议使用它来获取排除日志中可见问题所需的网络跟踪。应用程序和 haproxy 的分析总会有一刻会产生分歧,网络跟踪是判断谁对谁错的唯一方法。通过 tcpdump 检测网络堆栈和 hypervisor 中的错误也很常见; - strace:它是 tcpdump 的伴侣。它将报告 HAProxy 真正看到的内容,并有助于区分操作系统负责的问题和 HAProxy 负责的问题。当怀疑 HAProxy 中存在错误时,通常需要 strace;
根据部署 HAProxy 的操作系统,可能会有某些额外的功能可用或需要。虽然 HAProxy 在许多平台上都受支持,但它主要是在 Linux 上开发的,这解释了为什么某些功能仅在此平台上可用。透明绑定和连接功能、对将连接绑定到特定网络接口的支持,以及将多个进程绑定到相同 IP 地址和端口的能力仅在 Linux 和 BSD 系统上可用,尽管只有 Linux 在内核端对传入请求进行负载均衡。在 Linux 上,还有许多额外功能和优化,包括对网络命名空间(也称为“容器”)的支持,允许 HAProxy 成为所有容器之间的网关,设置客户端连接上的 MSS、Netfilter 标记和 IP TOS 字段的能力,在监听侧支持 TCP FastOpen,TCP 用户超时以在内核检测到客户端消失时快速终止连接(在配置超时之前),TCP 拼接以允许内核在连接的两侧之间转发数据,从而避免多次内存复制,启用“defer-accept”绑定选项以仅在内核缓冲区中数据可用时才接收传入连接通知的能力,以及发送带有 ACK 确认连接的请求的能力(有时称为“piggy-back”),这通过“tcp-smart-connect”选项启用。在 Linux 上,HAProxy 还非常小心地操作 TCP 延迟 ACK,以在网络上节省尽可能多的数据包。有些系统有一个不可靠的时钟,它在过去和未来之间来回跳跃。这过去发生在一些 NUMA 系统中,其中多个处理器没有看到完全相同的一天时间,最近在虚拟化环境中变得更常见,其中虚拟时钟与真实时钟没有关系,导致巨大的时间跳跃(有时观察到长达 30 秒)。这通常会对超时强制执行造成很多麻烦。由于这些系统的缺陷,HAProxy 维护自己的单调时钟,该时钟基于系统时钟,但会测量和补偿漂移。这确保了即使系统时钟非常差,计时器仍能保持合理准确,并且超时继续工作。请注意,此问题会影响在此类系统上运行的所有软件,并非 HAProxy 特有。常见的影响是虚假超时或应用程序冻结。因此,如果在此类系统上检测到此行为,则必须修复它,无论 HAProxy 是否保护自己免受其影响。在 Linux 上,新启动的进程可以与前一个进程通信以重用其监听文件描述符,以便在进程替换期间监听套接字不会中断。
HAProxy 可以通过 Lua 嵌入式语言进行构建,这为复杂的请求或响应操作、路由决策、统计处理等领域开辟了广泛的新可能性。使用 Lua 甚至可以建立到其他服务器的并行连接以交换信息。这样,例如,开发身份验证系统就成为可能(尽管很复杂)。有关如何使用 Lua 的更多信息,请参阅文件“doc/lua-api/index.rst”中的文档。
管理员可以在任何时候通过 CLI 连接并启用各种内部子系统的跟踪。默认提供不同级别的详细信息,因此实际上可以检索从每条请求一行到每条请求 500 行的内容。过滤器以及自动捕获开/关/暂停机制可用,因此实际上可以等待某个特定事件并详细观察它。这对于诊断故障服务器和客户端的协议违规或拒绝服务攻击非常方便。
典型的CPU使用率数据显示,在TCP或HTTP关闭模式下,HAProxy占用15%的处理时间,而内核占用85%;在HTTP保持活动模式下,HAProxy占用约30%,内核占用约70%。这意味着操作系统及其调优对整体性能有很大影响。用户的用途各不相同,有些关注带宽,有些关注请求速率,有些关注连接并发性,还有些关注SSL性能。本节旨在提供一些帮助完成这项任务的要素。重要的是要记住,每项操作都有成本,因此每项单独的操作都会在其他操作的基础上增加开销,这在某些情况下可能微不足道,而在其他情况下则可能占主导地位。处理连接请求时,我们可以说:- 转发数据成本低于解析请求或响应头;- 解析请求或响应头成本低于建立然后关闭与服务器的连接;- 建立并关闭连接成本低于TLS恢复操作;- TLS恢复操作成本低于包含密钥计算的完整TLS握手;- 空闲连接的CPU成本低于缓冲区中包含数据的连接;- TLS上下文所需的内存比包含数据的连接还要多;因此,实际上,处理有效载荷字节比处理标头字节便宜,因此通过大对象(每单位容量请求较少)比通过小对象(每单位容量请求较多)更容易实现高网络带宽。这解释了为什么最大带宽始终用大对象来衡量,而请求速率或连接速率用小对象来衡量。有些操作可以在分布在多个CPU上的多个进程中很好地扩展,而另一些则不然。网络带宽扩展不太远,因为对于大对象来说,CPU很少成为瓶颈,主要是网络带宽和到达网络接口的数据总线。由于处理本地端口表时系统中的一些锁,连接速率在多个处理器上扩展不佳。持久连接上的请求速率扩展非常好,因为它不涉及太多内存或网络带宽,也不需要访问锁定的结构。TLS密钥计算扩展非常好,因为它完全受限于CPU。TLS恢复扩展中等,但在大约4个进程时达到极限,此时访问共享表的开销抵消了从更多电源获得的微小增益。经过精心调优的系统可以达到的性能数字在以下范围内。重要的是将它们视为数量级,并根据处理器、IRQ设置、内存类型、网络接口类型、操作系统调优等期望任何方向的显着变化。以下数字是在运行频率为3.7 GHz的Core i7上找到的,配备双端口10 Gbps网卡,运行Linux kernel 3.10、HAProxy 1.6和OpenSSL 1.0.2。HAProxy作为单个进程在单个专用CPU核心上运行,另外两个核心专用于网络中断:- 最大网络带宽:明文情况下,对象大小为256 kB或更高时为20 Gbps,41kB或更高时为10 Gbps;- TLS流量:使用AES256-GCM密码且对象较大时为4.6 Gbps;- 客户端到服务器的TCP连接速率:每秒83000次;- 客户端到服务器的HTTP连接速率:每秒82000次;- HTTP请求速率(服务器关闭模式):每秒97000次(与客户端保持活动,与服务器关闭);- HTTP请求速率(端到端保持活动模式):每秒243000次;- 过滤的TCP连接速率(抗DDoS):每秒300000次;- HTTPS请求速率(保持活动模式,持久TLS连接):每秒160000次;- HTTPS请求速率(使用TLS恢复连接):每秒13100次;- HTTPS连接速率(使用RSA2048重新协商TLS连接):每秒1300次;- 并发饱和连接:每GB RAM约20000个,包括系统缓冲区所需的内存;通过仔细调优可以做得更好,但这个结果很容易实现。- 并发TLS连接(仅客户端侧):每GB RAM约8000个,包括系统缓冲区所需的内存;- 并发端到端TLS连接(两侧):每GB RAM约5000个,包括系统缓冲区所需的内存;最近的一项基准测试显示,在AWS上运行64核ARM Graviton2处理器上启用了多线程的HAProxy 2.4,达到了每秒200万次HTTPS请求,响应时间低于毫秒,流量达到100 Gbps:https://www.haproxy.com/blog/haproxy-forwards-over-2-million-http-requests-per-second-on-a-single-aws-arm-instance/因此,一个好的经验法则是,请求速率在TLS保持活动和TLS恢复之间、TLS恢复和TLS重新协商之间都除以10,而在HTTP保持活动和HTTP关闭之间只除以3。另一个好的经验法则是记住具有AES指令的高频核心每核心可以处理大约20 Gbps的AES-GCM。另一个好的经验法则是考虑在同一服务器上,HAProxy将能够饱和:- 大约5-10个静态文件服务器或缓存代理;- 大约100个防病毒代理;- 大约100-1000个应用服务器,具体取决于所使用的技术。
HAProxy是一个受GPLv2许可覆盖的开源项目,这意味着每个人都可以重新分发它,前提是应要求提供源代码,尤其是如果进行了任何修改。HAProxy以名为“master”或“mainline”的主要开发分支进行演进,一旦代码被认为是稳定的,就会从中派生出新的分支。许多网站自愿在生产环境中运行一些开发分支,要么是为了参与项目,要么是因为他们需要一个尖端功能,他们的反馈对于修复错误和判断正在开发的版本的整体质量和稳定性非常有价值。当代码足够稳定时创建的新分支构成一个稳定版本,通常会维护数年,因此即使您没有使用最新版本,也没有迁移到更新分支的紧迫性。一旦发布稳定分支,它可能只会收到错误修复,并且很少进行次要功能更新,除非这能让用户的生活更轻松。所有进入稳定分支的修复程序都必须来自master分支。这保证了升级后不会丢失任何修复程序。因此,如果您修复了一个错误,请针对master分支而不是稳定分支制作补丁。您甚至可能会发现它已经被修复了。此过程还确保稳定分支中的回归非常罕见,因此始终没有理由不升级到当前分支中的最新版本。分支编号由两个用点分隔的数字组成,例如“1.6”。自1.9以来,第二个数字为奇数的分支主要关注敏感的技术更新,更针对高级用户,因为它们比其他分支更容易引发更多错误。它们仅维护约一年,不得部署在不能紧急回滚的地方。完整版本包括一个或两个子版本号,指示修复级别。例如,版本1.5.14是版本1.5.0发布后分支1.5中的第14个修复版本。它包含126个针对单个错误的修复程序,24个文档更新以及75个其他反向移植补丁,其中大部分是修复上述126个错误所需的。稳定分支中的现有功能可能永远不会被修改或删除,以确保在同一分支内的升级始终是无害的。HAProxy可从多个来源获取,发布节奏不同:- 官方社区网站:https://haproxy.cn/:该网站提供最新开发版本、所有稳定版本以及每个分支的夜间快照的源代码。发布周期不快,稳定版本或开发快照之间相隔数月。非常旧的版本仍然在那里得到支持。所有内容均仅以源代码形式提供,因此来自那里的任何内容都需要重新构建和/或重新打包;- GitHub:https://github.com/haproxy/haproxy/:这是仅针对开发分支的镜像,提供与问题跟踪器、持续集成和代码覆盖工具的集成。这专门用于贡献者;- 许多操作系统,例如Linux发行版和BSD端口。这些系统通常提供长期维护的版本,这些版本并不总是包含来自官方版本的所有修复程序,但至少包含关键修复程序。对于不寻求高级配置且只想保持更新容易的大多数用户来说,这通常是一个不错的选择;- 来自http://www.haproxy.com/的商业版本:这些是针对各种操作系统构建或作为设备提供的受支持专业软件包,基于最新的稳定版本,并包含从下一个版本反向移植的许多功能,这些功能有强烈的需求。对于寻求最新功能、稳定分支的可靠性、最快的错误修复响应时间或仅仅是在开源产品之上寻求支持合同的用户来说,这是最佳选择;为了确保您使用的版本是您分支中的最新版本,您需要按以下方式进行:- 验证您正在运行哪个HAProxy可执行文件:某些系统默认附带它,管理员将其版本安装在系统上的其他位置,因此在启动脚本中验证使用哪个版本非常重要;- 确定您的HAProxy版本来自哪个来源。为此,通常只需键入“haproxy -v”。开发版本将显示如下,分支编号后带有“dev”一词:HAProxy version 2.4-dev18-a5357c-137 2021/05/09 - https://haproxy.cn/稳定版本将显示如下,操作系统供应商提供的未修改稳定版本也将显示如下:HAProxy version 1.5.14 2015/07/02稳定版本的夜间快照将显示如下,版本后带有一个十六进制序列,日期为快照日期而非发布日期:HAProxy version 1.5.14-e4766ba 2015/07/29任何其他格式都可能表示具有其自己的补丁集的系统特定软件包。例如,HAProxy Enterprise版本将显示为以下格式(<branch>-<latest commit>-<revision>):HAProxy version 1.5.0-994126-357 2015/07/02请注意,历史上2.4之前的版本过去常常在“HA”和“Proxy”之间使用连字符报告进程名称,包括上面调整为仅显示正确格式的版本,因此最好忽略这个词或在脚本中使用宽松匹配。此外,现代版本会添加一个链接到项目主页的URL。最后,版本2.1及更高版本将包含一行“Status”,指示该版本是否可用于生产,如果是,则到何时,以及指向影响此版本的已知错误列表的链接。- 对于系统特定软件包,您必须向供应商的软件包存储库或更新系统查询,以确保您的系统仍受支持,并且仍为您的分支提供修复程序。对于来自haproxy.org的社区版本,只需访问该网站,验证您分支的状态,并将最新版本与您的版本进行比较,看看您是否是最新版本。如果不是,您可以升级。如果您的分支不再维护,您肯定已经非常晚了,必须考虑升级到更近的分支(这样做时请仔细阅读README)。HAProxy必须根据其来源进行更新。通常它遵循系统供应商升级软件包的方式。如果是从源代码获取的,请在提取源代码后阅读源代码目录中的README文件,并按照适用于您的操作系统的说明进行操作。
HAProxy 与下面列出的一些产品集成得相当好,因此即使它们不直接与 HAProxy 相关,也在此处提及。
Apache是事实上的标准HTTP服务器。它是一个非常完整和模块化的项目,支持文件服务和动态内容。它可以作为某些应用服务器的前端。它甚至可以代理请求和缓存响应。在所有这些用例中,通常需要一个前端负载均衡器。Apache可以以各种模式工作,有些模式比其他模式更重。某些模块仍然需要更重的pre-forked模型,并且会阻止Apache在大量连接下很好地扩展。在这种情况下,HAProxy可以通过将每服务器连接限制强制设置为安全值来提供巨大帮助,并将显着加快服务器速度并保留其资源,以便应用程序更好地使用。Apache可以使用“mod_rpaf”扩展从X-Forwarded-For标头中提取客户端地址。当在HAProxy配置中指定“option forwardfor”时,HAProxy会自动提供此标头。当暴露在互联网上时,HAProxy还可能为Apache提供良好的保护,它可以更好地抵抗各种类型的DoS攻击。
NGINX是第二个事实上的标准HTTP服务器。就像Apache一样,它涵盖了广泛的功能。NGINX是基于与HAProxy相似的模型构建的,因此它处理数万个并发连接没有问题。当用作某些应用程序的网关时(例如使用包含的PHP FPM),设置一些前端连接限制以减少PHP应用程序上的负载通常是有益的。HAProxy在此将非常有用,既可以作为常规负载均衡器,也可以作为流量调节器,通过减轻PHP的负担来加快PHP的速度。此外,由于这两种产品都使用非常少的CPU(归功于它们的事件驱动架构),因此通常很容易将它们都安装在同一系统上。NGINX实现了HAProxy的PROXY协议,因此HAProxy可以轻松地将客户端连接信息传递给NGINX,以便应用程序获得所有相关信息。一些基准测试还表明,对于大型静态文件服务,在NGINX前面实施HAProxy上的一致哈希可能通过优化操作系统的缓存命中率而受益,缓存命中率基本上乘以服务器节点的数量。
Varnish是一个智能缓存反向代理,可能最好描述为Web应用程序加速器。Varnish不实现SSL/TLS,并希望将其所有CPU周期都用于其最擅长的事情。Varnish还实现了HAProxy的PROXY协议,因此HAProxy可以非常容易地部署在Varnish前面作为SSL卸载器和负载均衡器,并向其传递所有相关的客户端信息。此外,当服务器提供了压缩对象时,Varnish自然支持从缓存中解压缩,但它不进行压缩。然后,当后端服务器未实现压缩时,HAProxy可用于压缩传出数据,尽管除非流量很低,否则在负载均衡器上进行压缩很少是个好主意。当在多个节点上构建大型缓存场时,HAProxy可以利用一致的URL哈希来智能地将负载分配给缓存节点并避免缓存重复,从而使总缓存大小成为所有缓存节点的总和。此外,在HAProxy上对非常小的哑对象进行短时间缓存有时可以节省网络往返,并减少HAProxy和Varnish节点的CPU负载。这只有在Varnish上未对这些对象进行处理时才可能(这通常被称为“favicon cache”的概念,通过它可以避免相当大比例的无用下游请求)。但是,不要在任何其他缓存前面长时间启用HAProxy缓存(超过几秒钟),这会显着使故障排除复杂化,而不会提供真正显着的节省。
Linux Virtual Server (LVS或IPVS)是Linux内核中包含的第4层负载均衡器。它在数据包级别工作,处理TCP和UDP。在大多数情况下,它更多是补充而不是替代方案,因为它根本没有第7层知识。Pound是另一个著名的负载均衡器。它比HAProxy简单得多,功能也少得多,但对于许多非常基本的设置,两者都可以使用。它的作者始终首先关注代码可审计性,并希望保持功能集较低。它的基于线程的架构在连接数较高时扩展性较差,但它是一个不错的产品。Pen是一个相当轻量级的负载均衡器。它支持SSL,使用其客户端IP地址的固定大小表来保持持久性。它支持面向数据包的模式,允许它在某种程度上支持直接服务器返回和UDP。它适用于小负载(持久性表只有2048个条目)。NGINX在一定程度上可以进行负载均衡,尽管这显然不是它的主要功能。生产流量用于检测服务器故障,负载均衡算法更加有限,并且粘性非常有限。但在某些简单的部署场景中,如果它已经存在,则可能是有意义的。好处是,由于它与HAProxy集成得非常好,因此在达到其限制后添加HAProxy也没有错。Varnish也对其后端服务器进行一些负载均衡,并且确实支持真正的健康检查。但是,它不实现粘性,因此就像NGINX一样,只要不需要粘性,这可能足以开始使用。类似地,由于HAProxy和Varnish集成得如此之好,因此很容易将其添加到组合中以补充功能集。
如果您想就任何事情联系开发人员或任何社区成员,最好的方式通常是通过邮件列表将您的消息发送到haproxy@formilux.org。请注意,此列表是公开的,其存档也是公开的,因此您应避免泄露敏感信息。那里有数千名具有不同经验水平的用户,即使是最复杂的问题通常也能相对较快地找到最佳答案。也欢迎提出建议。对于使用电子邮件有困难的用户,可以在http://discourse.haproxy.org/上使用Discourse平台。但是请记住,阅读那里问题的人较少,并且大多数问题由一个非常小的团队处理。在任何情况下,请对那些花费业余时间帮助他人的人保持耐心和尊重。如果您认为您发现了一个错误但不确定,最好在邮件列表上报告。如果您非常确信自己发现了一个错误,并且您的版本在其分支中是最新的,并且您已经有一个GitHub帐户,请随时直接访问https://github.com/haproxy/haproxy/并提交一个问题,其中包含所有可能可用的详细信息。同样,这是公开的,因此请小心不要发布您以后可能会后悔的信息。由于问题跟踪器显示为非常长的线程,请避免粘贴非常长的转储(几百行或更多),而是将其作为附件。如果您发现了您绝对确定可以被视为关键安全问题的问题,如果在一个公共场所讨论会给许多用户带来严重麻烦,那么您可以将其与重现器一起发送到security@haproxy.org。一个由值得信赖的开发人员组成的小团队将收到它,并能够提出修复方案。我们通常不使用禁运,一旦修复可用,它就会被合并。在某些罕见情况下,可能会与软件供应商协调发布。请注意,此过程通常会搞乱每个人的工作,并且仓促的发布有时会引入新错误,因此除非严格必要,否则最好避免;因此,通常很少考虑那些不必要地造成这种额外负担的报告,并且看到您的工作得到认可的最佳方式通常是提供一个可行的修复程序,该修复程序将出现在变更日志中。