本文档不提供任何配置方面的帮助或提示,但它解释了在哪里可以找到相关文档。下面的概述旨在帮助您按名称搜索章节并在文档中导航。致文档贡献者:本文档的格式为每行 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.3.9. | ||
| 3.3.10. | ||
| 3.3.11. | ||
| 3.3.12. | ||
| 3.3.13. | ||
| 3.3.14. | ||
| 3.3.15. | ||
| 3.3.16. | ||
| 3.4. | ||
| 3.4.1. | ||
| 3.4.2. | ||
| 3.4.3. | ||
| 3.5. | ||
| 3.6. | ||
4. |
配套产品和替代方案 | |
| 4.1. | ||
| 4.2. | ||
| 4.3. | ||
| 4.4. |
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 的交换机。它通常是无状态的,也可以是有状态的(考虑数据包所属的会话,称为 layer4-LB 或 L4),如果数据包未被修改,可能支持 DSR(直接服务器返回,无需再次通过 LB),但几乎不提供内容感知。这种技术非常适合网络级负载均衡,尽管有时也用于高速的基本服务器负载均衡。第二种技术在会话内容上运行。它要求将输入流重新组装并作为一个整体进行处理。内容可能会被修改,并且输出流被分段为新的数据包。因此,它通常由代理执行,它们通常被称为第 7 层负载均衡器或 L7。这意味着两侧有两个不同的连接,并且输入和输出数据包大小和数量之间没有关系。客户端和服务器不需要使用相同的协议(例如 IPv4 与 IPv6,明文与 SSL)。操作总是有状态的,并且返回流量必须通过负载均衡器。额外的处理会带来成本,因此并不总是能够达到线速,尤其是对于小数据包。另一方面,它提供了广泛的可能性,并且通常由纯软件实现,即使嵌入到硬件设备中也是如此。这种技术非常适合服务器负载均衡。基于数据包的负载均衡器通常以直通模式部署,因此它们安装在流量的正常路径上,并根据配置分流流量。返回流量不一定通过负载均衡器。可能会对网络目标地址应用一些修改,以便将流量导向正确的目的地。在这种情况下,返回流量必须通过负载均衡器。如果路由无法实现这一点,负载均衡器也可以将其自身的 IP 地址替换为数据包的源地址,以强制返回流量通过它。基于代理的负载均衡器作为具有自己 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 连接,连接到服务器并将这些套接字连接在一起,允许流量在两个方向上流动; - HTTP 反向代理(在 HTTP 术语中称为“网关”):它将自己呈现为服务器,接收在侦听 TCP 套接字上接受的连接上的 HTTP 请求,并将来自这些连接的请求使用不同的连接传递给服务器。 - SSL 终止器/发起器/卸载器:SSL/TLS 可用于来自客户端的连接、流向服务器的连接,甚至用于两个连接。 - TCP 规范器:由于连接由操作系统在本地终止,因此两侧之间没有关系,因此异常流量(例如无效数据包、标志组合、窗口通告、序列号、不完整连接(SYN 洪水))将不会传递到另一侧。这可以保护脆弱的 TCP 堆栈免受协议攻击,还允许优化与客户端的连接参数,而无需修改服务器的 TCP 堆栈设置。 - HTTP 规范器:配置为处理 HTTP 流量时,只传递有效的完整请求。这可以防止许多基于协议的攻击。此外,规范中允许的协议偏差会得到修复,以便它们不会在服务器上引起问题(例如,多行标头)。 - HTTP 修复工具:它可以修改/修复/添加/删除/重写 URL 或任何请求或响应标头。这有助于解决复杂环境中的互操作性问题。 - 基于内容的交换机:它可以考虑请求中的任何元素来决定将请求或连接传递给哪个服务器。因此,可以在同一端口上处理多种协议(例如 HTTP、HTTPS、SSH)。 - 服务器负载均衡器:它可以对 TCP 连接和 HTTP 请求进行负载均衡。在 TCP 模式下,负载均衡决策针对整个连接进行。在 HTTP 模式下,决策按请求进行。 - 流量调节器:它可以在各个点应用速率限制,保护服务器免受过载,根据内容调整流量优先级,甚至通过标记数据包将此类信息传递给较低层和外部网络组件。 - 针对 DDoS 和服务滥用的保护:它可以维护每个 IP 地址、URL、cookie 等的大量统计信息,并检测何时发生滥用,然后采取行动(减慢攻击者、阻止他们、将他们发送到过时的内容等)。 - 网络故障排除的观察点:由于日志中报告的信息的精确性,它通常用于缩小一些与网络相关的问题。 - HTTP 压缩卸载器:它可以压缩未被服务器压缩的响应,从而减少连接不良或使用高延迟移动网络的客户端的页面加载时间。 HAProxy 不是: - 显式 HTTP 代理,即浏览器用于访问互联网的代理。有出色的开源软件专门用于此任务,例如 Squid。然而,HAProxy 可以安装在此类代理前面以提供负载均衡和高可用性。 - 缓存代理:它将按原样返回从服务器接收到的内容,并且不会干扰任何缓存策略。有出色的开源软件用于此任务,例如 Varnish。HAProxy 可以安装在此类缓存前面以提供 SSL 卸载和通过智能负载均衡实现的可扩展性。 - 数据清除器:它不会修改请求或响应的正文。 - Web 服务器:在启动期间,它将自己隔离在 chroot jail 中并放弃其权限,因此一旦启动,它将不会执行任何文件系统访问。因此,它不能转变为 Web 服务器。有出色的开源软件用于此目的,例如 Apache 或 Nginx,HAProxy 可以安装在它们前面以提供负载均衡和高可用性。 - 基于数据包的负载均衡器:它不会查看 IP 数据包或 UDP 数据报,不会执行 NAT,更不会执行 DSR。这些是较低层的任务。一些基于内核的组件(例如 IPVS(Linux Virtual Server))已经做得很好,并且与 HAProxy 完美互补。
HAProxy 是一个单线程、事件驱动、非阻塞引擎,结合了非常快的 I/O 层和基于优先级的调度程序。由于其设计目标是数据转发,因此其架构经过优化,可以以最少的操作尽快移动数据。因此,它实现了一个分层模型,在每个级别提供绕过机制,确保数据除非需要否则不会到达更高级别。大部分处理都在内核中执行,HAProxy 尽力通过提供一些提示或避免某些操作(当它猜测它们可以在以后分组时)来帮助内核尽快完成工作。因此,典型的数字显示,在 TCP 或 HTTP close 模式下,HAProxy 占用的处理时间为 15%,而内核占用的处理时间为 85%;在 HTTP keep-alive 模式下,HAProxy 占用的处理时间约为 30%,而内核占用的处理时间为 70%。一个进程可以运行许多代理实例;据报道,单个进程中多达 300000 个不同代理的配置运行良好。因此,通常不需要为所有实例启动多个进程。可以让 HAProxy 在多个进程上运行,但这有一些限制。通常在 HTTP close 或 TCP 模式下没有意义,因为内核端在某些操作(例如 connect())方面扩展性不是很好。它对于 HTTP keep-alive 模式扩展性很好,但单个进程可以实现的性能通常比常见需求高出一个数量级。然而,当用作 SSL 卸载器时,它确实有意义,并且多进程模式很好地支持此功能。HAProxy 只需要 haproxy 可执行文件和一个配置文件即可运行。对于日志记录,强烈建议配置适当的 syslog 守护程序和日志轮换。配置文件在启动前解析,然后 HAProxy 尝试绑定所有侦听套接字,如果任何操作失败则拒绝启动。过了这一点,它就不能再失败了。这意味着没有运行时故障,如果它接受启动,它将一直工作直到停止。HAProxy 启动后,它只做 3 件事: - 处理传入连接; - 定期检查服务器的状态(称为健康检查); - 与其他 haproxy 节点交换信息。处理传入连接是迄今为止最复杂的任务,因为它依赖于许多配置可能性,但可以总结为以下 9 个步骤: - 从属于称为“frontend”的配置实体的侦听套接字接受传入连接,该实体引用一个或多个侦听地址; - 对这些连接应用前端特定的处理规则,这可能导致阻止它们、修改某些标头或拦截它们以执行一些内部小程序(例如统计信息页面或 CLI); - 将这些传入连接传递给代表服务器场(称为“backend”)的另一个配置实体,其中包含服务器列表和此服务器场的负载均衡策略; - 对这些连接应用后端特定的处理规则; - 根据负载均衡策略决定将连接转发到哪个服务器; - 对响应数据应用后端特定的处理规则; - 对响应数据应用前端特定的处理规则; - 发出日志以报告详细发生的情况; - 在 HTTP 中,循环回到第二步以等待新请求,否则关闭连接。前端和后端有时被视为半代理,因为它们只查看端到端连接的一侧;前端只关心客户端,而后端只关心服务器。HAProxy 还支持全代理,全代理是前端和后端的精确联合。当需要 HTTP 处理时,配置通常会拆分为前端和后端,因为它们提供了很多可能性,因为任何前端都可以将连接传递给任何后端。对于纯 TCP 代理,使用前端和后端很少能带来好处,并且配置可能更易于阅读全代理。
本节将列举 HAProxy 实现的许多功能,其中一些是任何现代负载均衡器通常期望的,而另一些则是 HAProxy 架构的直接优势。更高级的功能将在下一节中详细介绍。
代理是在客户端和服务器之间通过两个独立连接传输数据的操作。HAProxy 在代理和连接管理方面支持以下基本功能: - 为服务器提供干净的连接,以保护它们免受任何客户端缺陷或攻击; - 侦听多个 IP 地址和/或端口,甚至是端口范围; - 透明接受:拦截针对不属于本地系统的任意 IP 地址的流量; - 服务器端口不需要与侦听端口相关,甚至可以通过固定偏移量进行转换(在范围内有用); - 透明连接:如果需要,在连接到服务器时欺骗客户端(或任何)IP 地址; - 在多站点 LB 中为服务器提供可靠的返回 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 ticket 可以从 CLI 更新,这为它们提供了通过频繁轮换 ticket 来实现完美前向保密的方法。
HAProxy 非常注重可用性。因此,它关心服务器状态,并关心向其他网络组件报告自己的状态: - 使用每个服务器参数持续监控服务器状态。这确保了服务器的路径可用于常规流量; - 健康检查支持上下转换的两种滞后,以防止状态抖动; - 检查可以发送到不同的地址/端口/协议:这使得检查被认为是多个服务代表的单个服务变得容易,例如 HTTP+HTTPS 服务器的 HTTPS 端口。 - 服务器可以跟踪其他服务器并同时宕机:这确保了托管多个服务的服务器可以原子地失败,并且不会将任何人发送到部分失败的服务器; - 代理可以部署在服务器上以监控负载和健康状况:服务器可能有兴趣独立于健康检查所能看到的内容报告其负载、操作状态、管理状态。通过在服务器上运行一个简单的代理,除了验证整个路径的健康检查之外,还可以考虑服务器对自身健康状况的看法; - 提供各种检查方法:TCP 连接、HTTP 请求、SMTP hello、SSL hello、LDAP、SQL、Redis、send/expect 脚本,所有这些都带/不带 SSL; - 状态更改在日志和统计信息页面中通知,并附带故障原因(例如,在检测到故障时收到的 HTTP 响应)。在发生此类更改时,还可以向可配置的地址发送电子邮件; - 服务器状态也会在统计信息界面上报告,可用于制定路由决策,以便根据其大小和/或健康状况将流量发送到不同的服务器场(例如,丢失 inter-DC 链路); - HAProxy 可以使用健康检查请求将信息传递给服务器,例如它们的名称、权重、服务器场中其他服务器的数量等,以便服务器可以根据这些知识调整其响应和决策(例如,推迟备份以保持更多 CPU 可用); - 服务器可以使用健康检查来报告比仅开/关更详细的状态(例如,我想停止,请停止发送新访问者); - HAProxy 本身可以向外部组件(例如路由器或其他负载均衡器)报告其状态,从而允许构建非常完整的、多路径和多层基础设施。
就像任何严肃的负载均衡器一样,HAProxy 非常关心可用性,以确保最佳的全球服务连续性: - 仅使用有效的服务器;其他服务器会自动从负载均衡场中驱逐;在某些条件下,仍然可以强制使用它们; - 支持优雅关机,以便可以将服务器从服务器场中取出,而不会影响任何连接; - 备份服务器在活动服务器宕机时自动使用并替换它们,以便在可能的情况下不会丢失会话。这也允许构建到达同一服务器的多条路径(例如,多个接口); - 当太多服务器宕机时,能够返回服务器场的全局失败状态。这与监控功能相结合,使得上游组件可以选择用于给定服务的不同 LB 节点; - 无状态设计使得构建集群变得容易:通过设计,HAProxy 尽力确保最高的服务连续性,而无需存储可能在发生故障时丢失的信息。这确保了接管尽可能无缝; - 与标准 VRRP 守护程序 keepalived 良好集成:HAProxy 轻松告知 keepalived 其状态,并能很好地应对浮动虚拟 IP 地址。注意:仅在基于集群的解决方案(Heartbeat...)上使用 IP 冗余协议(VRRP/CARP),因为它们提供了最快、最无缝、最可靠的切换。
HAProxy 提供了一套相当完整的负载均衡功能,其中大部分不幸在许多其他负载均衡产品中不可用: - 支持不少于 9 种负载均衡算法,其中一些适用于输入数据以提供无限的可能性列表。最常见的包括循环(对于短连接,依次选择每个服务器)、leastconn(对于长连接,选择连接数最少的服务器中最近使用最少的服务器)、source(对于 SSL 场或终端服务器场,服务器直接取决于客户端的源地址)、URI(对于 HTTP 缓存,服务器直接取决于 HTTP URI)、hdr(服务器直接取决于特定 HTTP 标头字段的内容)、first(对于短命虚拟机,所有连接都打包在最小可能的服务器子集上,以便可以关闭未使用的服务器); - 上述所有算法都支持每个服务器权重,因此可以适应服务器场中不同代的服务器,或将一小部分流量导向特定服务器(调试模式、运行下一个版本的软件等); - 循环、leastconn 和一致性哈希支持动态权重;这允许从 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 的最大空闲时间和持续时间,可确保在永不关闭的设备(智能手机、电视、家用电器)上平稳停止粘性,而无需将其存储在持久存储上; - 多个服务器条目可以共享相同的粘性键,这样当一条路径宕机时,多路径环境中的粘性不会丢失; - soft-stop 确保只有具有粘性信息的用户才能继续访问分配给他们的服务器,但不会有新用户去那里。
HAProxy 使用广泛的“样本获取函数”集支持信息采样。原理是提取称为样本的信息片段,供立即使用。这用于粘性、构建条件、在日志中生成信息或丰富 HTTP 标头。可以从各种来源获取样本: - 常量:整数、字符串、IP 地址、二进制块; - 进程:日期、环境变量、服务器/前端/后端/进程状态、字节/连接计数/速率、队列长度、随机生成器... - 变量:每个会话、每个请求、每个响应变量; - 客户端连接:源和目标地址和端口,以及所有相关的统计计数器; - SSL 客户端会话:协议、版本、算法、密码、密钥大小、会话 ID、所有客户端和服务器证书字段、证书序列号、SNI、ALPN、NPN、客户端对某些扩展的支持; - 请求和响应缓冲区内容:偏移量/长度处的任意有效负载、数据长度、RDP cookie、SSL hello 类型解码、TLS SNI 解码; - HTTP(请求和响应):方法、URI、路径、查询字符串参数、状态代码、标头值、位置标头值、cookie、捕获、身份验证、正文元素; 然后,样本可以通过许多称为“转换器”的操作符进行一些转换。转换器消耗一个样本并生成一个新样本,可能是完全不同的类型。例如,转换器可用于仅返回输入字符串的整数长度,或将字符串转换为大写。在最终使用之前,可以对样本应用任意数量的转换器。在所有可用的样本转换器中,以下是使用最常见的: - 算术和逻辑运算符:它们可以对输入数据执行高级计算,例如计算比率、百分比或简单地从一个单位转换为另一个单位; - IP 地址掩码在需要按更大网络分组某些地址时非常有用; - 数据表示:URL 解码、base64、hex、JSON 字符串、哈希; - 字符串转换:提取固定位置、固定长度的子字符串、提取围绕特定分隔符的特定字段、提取特定单词、更改大小写、应用基于正则表达式的替换; - 日期转换:转换为 HTTP 日期格式、将本地转换为 UTC 反之亦然、添加或删除偏移量; - 在 stick table 中查找条目以查找统计信息或分配的服务器; - 来自文件的基于 map 的键到值转换(主要用于地理定位)。
映射是一种强大的转换器类型,它通过在启动时将一个两列文件加载到内存中,然后从第一列查找每个输入样本,如果找到条目,则返回第二列中的相应模式,否则返回默认值。输出信息也是一个样本,它可以经历其他转换,包括其他映射查找。映射最常用于将客户端的 IP 地址转换为 AS 号或国家代码,因为它们支持网络地址的最长匹配,但它们可以用于各种其他目的。它们的部分优势在于它们可以从 CLI 或通过其他样本的某些操作进行动态更新,从而使它们能够存储和检索后续访问之间的信息。另一个优势来自基于二进制树的索引,这使得它们即使包含数十万个条目也极其快速,从而使地理位置的设置非常便宜且容易。
HAProxy 中的大多数操作都可以有条件。通过使用逻辑运算符(AND、OR、NOT)组合多个 ACL 来构建条件。每个 ACL 都是一系列基于以下元素的测试: - 用于检索要测试元素的样本获取方法; - 可选的一系列转换器来转换元素; - 要匹配的模式列表; - 用于指示如何将模式与样本进行比较的匹配方法 例如,样本可以从 HTTP“Host”标头中获取,然后可以将其转换为小写,然后使用正则表达式匹配方法与许多正则表达式模式匹配。从技术上讲,ACL 是在与 map 相同的核心上构建的,它们共享完全相同的内部结构、模式匹配方法和性能。唯一真正的区别是,它们不是返回样本,而是只返回“找到”或“未找到”。在使用方面,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、删除查询字符串、如果缺少则附加斜杠等; - 所有操作都支持基于 ACL 的条件;
HAProxy 做了很多工作来最大限度地提高服务可用性,为此它付出了巨大的努力来保护服务器免受过载和攻击。第一点也是最重要的一点是,只有完整且有效的请求才会转发到服务器。最初的原因是 HAProxy 需要找到它需要与字节流保持同步的协议元素,第二个原因是直到请求完成,无法知道某些元素是否会改变其语义。直接的好处是服务器不会暴露在无效或不完整的请求中。这是一种非常有效的防御慢速攻击的方法,对 HAProxy 几乎没有影响。另一个重要点是 HAProxy 包含用于存储请求和响应的缓冲区,并且通过仅在请求完整时才将请求发送到服务器并通过本地网络非常快速地读取整个响应,服务器端连接的使用时间非常短,这最大限度地保护了服务器资源。对此的直接扩展是 HAProxy 可以人为地限制服务器的并发连接数或未完成请求数,这保证了服务器即使在流量高峰期间持续以 100% 的容量运行也不会过载。所有多余的请求都将简单地排队,以便在一个槽释放时进行处理。最终,这种巨大的资源节省最常确保更好的服务器响应时间,使其最终比使服务器过载更快。排队的请求可以重新分派到其他服务器,甚至可以在客户端中止时在队列中中止,这也保护了服务器免受“重新加载效应”的影响,即访问者在缓慢加载的页面上每次点击“重新加载”通常会诱发新请求并使服务器保持过载状态。慢启动机制还保护重新启动的服务器免受高流量水平的影响,而它们仍在完成启动或编译一些类。关于协议级保护,可以放宽 HTTP 解析器以接受不符合标准但无害的请求或响应,甚至可以修复它们。这允许在开发修复程序时可以访问错误的应用程序。同时,违规消息会被完全捕获,并附带详细报告,帮助开发人员发现应用程序中的问题。最危险的协议违规得到适当的检测和处理和修复。例如,如果值完全相同,则修复具有两个 Content-length 标头的格式错误请求或响应,如果它们不同,则拒绝,因为它会成为安全问题。协议检查不限于 HTTP,它也适用于其他协议,例如 TLS 或 RDP。当检测到协议违规或攻击时,有多种选项可以响应用户,例如返回常见的“HTTP 400 bad request”、使用 TCP 重置关闭连接,或者在长时间延迟后伪造错误(“tarpit”)以迷惑攻击者。所有这些都有助于保护服务器,通过阻止违规客户端继续进行变得非常昂贵的攻击。HAProxy 还提出了一些更高级的选项来防止意外数据泄漏和会话交叉。它不仅可以记录可疑的服务器响应,还可以记录并选择性地阻止可能影响给定访问者机密性的响应。一个这样的例子是可缓存响应中出现的缓存 cookie,它可能导致中间缓存将其传递给另一个访问者,导致意外的会话共享。
日志记录对于负载均衡器来说是一个极其重要的功能,首先是因为负载均衡器通常被错误地指责为导致它所揭示的问题,其次是因为它位于基础设施中的关键点,需要分析所有正常和异常活动并与其他组件关联。HAProxy 提供非常详细的日志,具有毫秒级精度和确切的连接接受时间,可以在防火墙日志中搜索(例如,用于 NAT 关联)。默认情况下,TCP 和 HTTP 日志非常详细,包含故障排除所需的一切,例如源 IP 地址和端口、前端、后端、服务器、计时器(请求接收持续时间、队列持续时间、连接设置时间、响应标头时间、数据传输时间)、全局进程状态、连接计数、队列状态、重试计数、详细的粘性操作和断开连接原因、具有安全输出编码的标头捕获。然后可以扩展或替换此格式以包含任何采样数据、变量、捕获,从而产生非常详细的信息。例如,可以记录客户端累积请求数或访问的不同 URL 数。日志级别可以使用标准 ACL 按请求调整,因此可以自动静默一些被认为是污染的日志,而当一小部分流量发生异常行为时(例如,源地址的 URL 或 HTTP 错误过多)发出警告。管理日志也会以其自己的级别发出,例如通知服务器的丢失或恢复。每个前端和后端可以使用多个独立的日志输出,这简化了多租户。日志最好通过 UDP 发送,可能采用 JSON 编码,并在可配置的行长度后截断,以保证交付。
HAProxy 提供一个基于 Web 的统计报告界面,具有身份验证、安全级别和范围功能。因此,可以为每个托管的客户提供他自己的页面,只显示他自己的实例。这个页面可以位于常规网站的一个隐藏 URL 部分,这样就不需要打开新的端口。这个页面还可以报告其他 HAProxy 节点的可用性,以便可以一目了然地发现一切是否按预期工作。视图是综合性的,可以访问许多详细信息(例如错误原因、最后访问和最后更改持续时间等),这些信息也可以作为 CSV 表格访问,其他工具可以导入该表格来绘制图表。该页面可以自动刷新,用作大型显示器上的监控页面。在管理模式下,该页面还允许更改服务器状态,以方便维护操作。
HAProxy 旨在在常规生产环境中保持极其稳定和安全地管理。它作为单个可执行文件提供,不需要任何安装过程。多个版本可以轻松共存,这意味着可以(并且建议)按重要性顺序逐步升级实例,而不是一次迁移所有实例。配置文件易于版本控制。配置检查是在离线完成的,因此不需要重新启动可能失败的服务。在配置检查期间,可能会检测到许多高级错误(例如,一个规则隐藏另一个规则,或者粘性将不起作用),并提出详细的警告和配置提示来修复它们。向后配置文件兼容性可以追溯到很远的时间,版本 1.5 仍然完全支持 13 年前编写的版本 1.1 的配置,而 1.6 仅放弃了对几乎未使用、过时的关键字的支持,这些关键字可以用不同的方式完成。配置和软件升级机制是平滑且不中断的,因为它允许新旧进程在系统上共存,每个进程处理自己的连接。系统状态、构建选项和库兼容性在启动时报告。一些高级功能允许应用程序管理员平稳地停止服务器,检测何时不再有活动,然后将其离线,停止它,升级它并确保它在升级期间不接收任何流量,然后通过正常路径再次测试它,而无需向公众开放,所有这些都无需接触 HAProxy。这确保了即使复杂的生产操作也可以在开放时间内完成,所有技术资源都可用。该进程尽量节省资源,使用内存池来节省分配时间并限制内存碎片,一旦发送内容就释放有效负载缓冲区,并支持强制执行严格的内存限制,超过此限制后连接必须等待缓冲区可用,而不是分配更多内存。该系统有助于保证在某些严格环境中的内存使用。命令行界面(CLI)可用作 UNIX 或 TCP 套接字,用于执行许多操作和检索故障排除信息。在此套接字上完成的所有操作都不需要更改配置,因此它主要用于临时更改。使用此界面,可以更改服务器的地址、权重和状态,查阅统计信息和清除计数器,转储和清除粘性表(可能按键标准选择性地清除),转储和终止客户端和服务器端连接,转储捕获的错误并详细分析错误的具体原因和位置,转储、添加和删除 ACL 和 map 中的条目,更新 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 splicing 以允许内核在连接的两侧之间转发数据,从而避免多次内存复制,启用“defer-accept”绑定选项的能力,以便仅在内核缓冲区中有数据可用时才收到传入连接通知,以及发送带有确认连接的 ACK 的请求的能力(有时称为“piggy-back”),这通过“tcp-smart-connect”选项启用。在 Linux 上,HAProxy 还非常注意操作 TCP 延迟 ACK,以在网络上节省尽可能多的数据包。有些系统有一个不可靠的时钟,它在过去和未来来回跳跃。这过去发生在一些 NUMA 系统中,其中多个处理器没有看到完全相同的日期时间,最近在虚拟化环境中变得更常见,其中虚拟时钟与真实时钟没有关系,导致巨大的时间跳跃(有时观察到长达 30 秒)。这通常会对超时强制执行造成很多麻烦。由于这些系统的缺陷,HAProxy 维护自己的单调时钟,该时钟基于系统时钟,但会测量和补偿漂移。这确保了即使系统时钟非常差,计时器仍能保持合理的准确性,并且超时继续工作。请注意,此问题会影响在此类系统上运行的所有软件,而不仅仅是 HAProxy。常见的影响是虚假超时或应用程序冻结。因此,如果在此类系统上检测到此行为,则必须修复它,而不管 HAProxy 是否保护自己免受其影响。
HAProxy 可以通过 Lua 嵌入式语言进行构建,这为复杂的请求或响应操作、路由决策、统计处理等领域开辟了广泛的新可能性。使用 Lua 甚至可以建立到其他服务器的并行连接以交换信息。这样,例如,开发身份验证系统就成为可能(尽管很复杂)。有关如何使用 Lua 的更多信息,请参阅文件“doc/lua-api/index.rst”中的文档。
典型的CPU使用率显示,在TCP或HTTP关闭模式下,HAProxy占用15%的处理时间,而内核占用85%;在HTTP keep-alive模式下,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;41 kB或更大对象,最大网络带宽10 Gbps;- 使用AES256-GCM密码套件和大型对象的TLS流量4.6 Gbps;- 每秒83000个从客户端到服务器的TCP连接;- 每秒82000个从客户端到服务器的HTTP连接;- 每秒97000个HTTP请求(服务器关闭模式,即客户端保持keep-alive,服务器关闭);- 每秒243000个HTTP请求(端到端keep-alive模式);- 每秒300000个过滤的TCP连接(抗DDoS)- 每秒160000个HTTPS请求(在持久TLS连接上使用keep-alive模式);- 每秒13100个HTTPS请求(使用TLS恢复连接);- 每秒1300个HTTPS连接(使用RSA2048重新协商的TLS连接);- 每GB内存约20000个并发饱和连接,包括系统缓冲区所需的内存;通过仔细调优可以做得更好,但这个结果很容易实现。- 每GB内存约8000个并发TLS连接(仅客户端侧),包括系统缓冲区所需的内存;- 每GB内存约5000个并发端到端TLS连接(两侧),包括系统缓冲区所需的内存;因此,一个好的经验法则是,请求速率在TLS keep-alive和TLS恢复之间,以及在TLS恢复和TLS重新协商之间都除以10,而在HTTP keep-alive和HTTP close之间只除以3。另一个好的经验法则是记住一个具有AES指令的高频核心每核心可以处理大约5 Gbps的AES-GCM。拥有更多核心很少有帮助(TLS除外),甚至由于频率较低而适得其反。通常少量高频核心更好。另一个好的经验法则是考虑在同一台服务器上,HAProxy将能够饱和:- 大约5-10个静态文件服务器或缓存代理;- 大约100个防病毒代理;- 大约100-1000个应用程序服务器,具体取决于所使用的技术。
HAProxy是一个受GPLv2许可覆盖的开源项目,这意味着任何人都可以重新分发它,前提是也应要求提供对源代码的访问权限,特别是如果进行了任何修改。HAProxy作为一个名为“master”或“mainline”的主要开发分支进行演进,一旦代码被认为是稳定的,就会从中派生出新的分支。许多网站自愿在生产环境中运行一些开发分支,要么是为了参与项目,要么是因为他们需要一个尖端功能,他们的反馈对于修复错误和判断正在开发版本的整体质量和稳定性非常有价值。当代码足够稳定时创建的新分支构成一个稳定版本,通常会维护数年,因此即使您使用的不是最新版本,也没有迁移到更新分支的紧迫性。一旦发布了稳定分支,它可能只接收错误修复,很少接收次要功能更新,除非这些更新能让用户的生活更轻松。所有进入稳定分支的修复都必须来自master分支。这保证了升级后不会丢失任何修复。因此,如果您修复了一个错误,请将补丁针对master分支,而不是稳定分支。您甚至可能会发现它已经被修复了。这个过程还确保了稳定分支中的回归非常罕见,因此没有任何借口不升级到当前分支中的最新版本。分支用两个数字加一个点来编号,例如“1.6”。一个完整的版本包括一个或两个子版本号,表示修复级别。例如,版本1.5.14是版本1.5.0发布后分支1.5中的第14个修复版本。它包含针对单个错误的126个修复,24个文档更新以及75个其他回溯补丁,其中大部分是修复上述126个错误所必需的。为了保证在同一分支内的升级始终无害,稳定分支中的现有功能永远不会被修改或删除。HAProxy可以从多个来源获得,发布节奏各不相同:- 官方社区网站:https://haproxy.cn/:该网站提供最新开发版本、所有稳定版本的源代码,以及每个分支的夜间快照。发布周期不快,稳定版本或开发快照之间相隔数月。非常旧的版本仍然在那里得到支持。所有内容都只提供源代码,因此来自那里的任何内容都需要重新构建和/或重新打包;- 许多操作系统,例如Linux发行版和BSD端口。这些系统通常提供长期维护的版本,这些版本并不总是包含官方版本的所有修复,但至少包含关键修复。对于大多数不寻求高级配置,只希望保持更新简单的用户来说,这通常是一个很好的选择;- 来自http://www.haproxy.com/的商业版本:这些是针对各种操作系统构建的受支持专业软件包或作为设备提供,基于最新的稳定版本,并包含一些从下一个版本回溯移植的、有强烈需求的功能。对于寻求最新功能、稳定分支的可靠性、最快的错误修复响应时间或仅仅是在开源产品之上需要支持合同的用户来说,这是最佳选择;为了确保您使用的版本是您分支中的最新版本,您需要按以下方式进行:- 验证您正在运行的HAProxy可执行文件:有些系统默认附带它,而管理员将他们的版本安装在系统的其他位置,因此在启动脚本中验证使用的是哪一个非常重要;- 确定您的HAProxy版本来自哪个来源。为此,通常只需输入“haproxy -v”。开发版本将如下所示,分支号后面带有“dev”字样:HA-Proxy version 1.6-dev3-385ecc-68 2015/08/18 稳定版本将如下所示,以及操作系统供应商提供的未修改稳定版本:HA-Proxy version 1.5.14 2015/07/02 稳定版本的夜间快照将如下所示,版本后面带有十六进制序列,以及快照日期而不是发布日期:HA-Proxy version 1.5.14-e4766ba 2015/07/29 任何其他格式都可能表明是具有自己补丁集的特定于系统的软件包。例如,HAProxy Enterprise版本将显示以下格式(<branch>-<latest commit>-<revision>):HA-Proxy version 1.5.0-994126-357 2015/07/02 - 对于特定于系统的软件包,您必须向供应商的软件包仓库或更新系统查询,以确保您的系统仍受支持,并且仍为您的分支提供修复。对于来自haproxy.org的社区版本,只需访问该网站,验证您的分支状态,并将最新版本与您的版本进行比较,看看您是否是最新版本。如果不是,您可以升级。如果您的分支不再维护,您肯定已经落后很多,必须考虑升级到更近的分支(这样做时请仔细阅读README)。HAProxy必须根据其来源进行更新。通常它遵循系统供应商升级软件包的方式。如果它是从源代码获取的,请在提取源代码后阅读源代码目录中的README文件,并按照适用于您的操作系统的说明进行操作。
HAProxy 与下面列出的一些产品集成得相当好,因此即使它们不直接与 HAProxy 相关,也在此处提及。
Apache是事实上的标准HTTP服务器。它是一个非常完整且模块化的项目,支持文件服务和动态内容。它可以作为某些应用服务器的前端。它甚至可以代理请求和缓存响应。在所有这些用例中,通常都需要一个前端负载均衡器。Apache可以以各种模式工作,有些模式比其他模式更重。某些模块仍然需要更重的pre-forked模型,并且会阻碍Apache在大量连接下很好地扩展。在这种情况下,HAProxy可以提供巨大的帮助,通过将每服务器连接限制强制到一个安全值,并将显着加快服务器速度并保留其资源,这些资源将更好地被应用程序使用。Apache可以使用“mod_rpaf”扩展从X-Forwarded-For标头中提取客户端地址。当HAProxy配置中指定“option forwardfor”时,它会自动填充此标头。当Apache暴露在互联网上时,HAProxy还可以为它提供很好的保护,它可以更好地抵抗各种类型的DoS攻击。
NGINX是第二个事实上的标准HTTP服务器。就像Apache一样,它涵盖了广泛的功能。NGINX是基于与HAProxy相似的模型构建的,因此它处理数万个并发连接没有问题。当用作某些应用程序(例如使用内置的PHP FPM)的网关时,设置一些前端连接限制以减少PHP应用程序的负载通常是有益的。HAProxy将作为常规负载均衡器和流量调节器在那里发挥明显作用,通过减轻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 哈希来智能地将负载分配到缓存节点,并避免缓存重复,从而使总缓存大小等于所有缓存节点的总和。
Linux Virtual Server (LVS 或 IPVS) 是包含在 Linux 内核中的第 4 层负载均衡器。它在数据包级别工作,处理 TCP 和 UDP。在大多数情况下,它更多是一个补充而不是替代品,因为它根本没有第 7 层知识。Pound 是另一个知名的负载均衡器。它比 HAProxy 简单得多,功能也少得多,但对于许多非常基本的设置,两者都可以使用。它的作者始终首先关注代码可审计性,并希望保持功能集较低。它的基于线程的架构在连接数高时扩展性较差,但它是一个好产品。Pen 是一个相当轻量级的负载均衡器。它支持 SSL,使用固定大小的客户端 IP 地址表来保持持久性。它支持一种面向数据包的模式,允许它在一定程度上支持直接服务器返回和 UDP。它适用于小负载(持久性表只有 2048 个条目)。NGINX 可以在一定程度上进行负载均衡,尽管这显然不是它的主要功能。生产流量用于检测服务器故障,负载均衡算法更有限,粘性非常有限。但在它已经存在的某些简单部署场景中可能是有意义的。好处是,由于它与 HAProxy 集成得非常好,当达到其限制时,以后再添加 HAProxy 也没有问题。Varnish 也对其后端服务器进行一些负载均衡,并且确实支持真正的健康检查。但是它不实现粘性,所以和 NGINX 一样,只要不需要粘性,这可能足以作为起点。同样,由于 HAProxy 和 Varnish 集成得非常好,因此很容易在以后将其添加到组合中以补充功能集。