入门指南

版本 1.7.14


本文档不提供任何配置方面的帮助或提示,但它解释了在哪里可以找到相关文档。下面的概述旨在帮助您按名称搜索章节并在文档中导航。致文档贡献者:本文档的格式为每行 80 列,缩进使用偶数个空格,不使用制表符。请严格遵守这些规则,以便在任何地方都能轻松打印。如果您添加章节,请更新下面的概述以便于搜索。
1. 可用文档

2.

负载均衡和负载均衡器的快速入门

3.

HAProxy 简介
3.1.
3.2.
3.3.
3.3.1.
3.3.2.
SSL
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 的交换机。通常是无状态的,它也可以是有状态的(考虑数据包所属的会话并称为 L4 负载均衡),如果数据包未被修改,则可以支持 DSR(直接服务器返回,无需再次通过负载均衡器),但几乎不提供内容感知。这项技术非常适合网络级别的负载均衡,尽管它有时用于非常基本的服务器负载均衡,速度非常快。第二种作用于会话内容。它要求输入流被重组并作为一个整体进行处理。内容可以被修改,输出流被分割成新的数据包。因此,它通常由代理执行,并且它们通常被称为 L7 负载均衡器。这意味着每侧存在两个独立的连接,并且输入和输出数据包的大小或计数之间没有关系。客户端和服务器不需要使用相同的协议(例如 IPv4 vs IPv6,明文 vs SSL)。操作总是会话状态的,并且返回流量必须通过负载均衡器。额外的处理是有成本的,因此并非总是能够达到线路速率,尤其是在数据包较小的情况下。另一方面,它提供了广泛的可能性,并且通常由纯软件实现,即使嵌入在硬件设备中。这项技术非常适合服务器负载均衡。基于数据包的负载均衡器通常以直通模式部署,因此它们安装在流量的正常路径上,并根据配置进行分流。返回流量不一定会通过负载均衡器。可能会对网络目标地址进行一些修改,以将流量导向正确的目的地。在这种情况下,返回流量必须通过负载均衡器。如果路由不允许,负载均衡器还可以用自己的地址替换数据包的源地址,以强制返回流量通过它。基于代理的负载均衡器作为具有自身 IP 地址和端口的服务器进行部署,而无需进行架构更改。有时这需要对应用程序进行一些调整,以便客户端能够正确地导向负载均衡器的 IP 地址而不是直接导向服务器的 IP 地址。一些负载均衡器可能需要调整服务器的响应以实现这一点(例如,HTTP Location 报头字段在 HTTP 重定向中使用)。一些基于代理的负载均衡器可能会拦截它们不拥有的地址的流量,并在连接到服务器时伪造客户端的地址。这允许它们像常规路由器或防火墙一样部署,采用一种非常类似于基于数据包的负载均衡器的直通模式。这尤其适用于结合了数据包模式和代理模式的产品。在这种情况下,DSR 显然仍然不可行,并且返回流量仍然必须路由回负载均衡器。一种非常可扩展的分层方法是拥有一个前端路由器,它接收来自多个负载均衡链路的流量,并使用 ECMP 将此流量分发到第一层的多个有状态数据包负载均衡器(L4)。这些 L4 负载均衡器反过来将流量传递给更多基于代理的负载均衡器(L7),这些负载均衡器必须解析内容以决定最终将接收流量的服务器。组件数量和流量的可能路径增加了故障的风险;在非常大的环境中,即使有少量组件永久出现故障并正在修复或更换,也是很正常的。没有意识到整个堆栈健康状况的负载均衡会严重降低可用性。因此,任何明智的负载均衡器都会验证它打算将流量发送到的组件仍然存活且可达,并且它将停止向故障组件发送流量。这可以通过各种方法来实现。最常见的方法是定期发送探测以确保组件仍然正常工作。这些探测称为“健康检查”。它们必须能够代表要解决的故障类型。例如,基于 ping 的检查无法检测到 Web 服务器已崩溃并且不再监听端口,而连接到端口将验证这一点,更高级的请求甚至可以验证服务器仍然正常工作并且它依赖的数据库仍然可访问。健康检查通常涉及几次重试,以涵盖偶尔的测量错误。检查之间的周期必须足够短,以确保在发生错误后故障组件不会使用太长时间。其他方法包括对发送到某个目的地的生产流量进行采样,以观察它是否被正确处理,以及驱逐返回不当响应的组件。然而,这需要牺牲一部分生产流量,并且并不总是可接受的。这两种机制的结合提供了两全其美,两者都用于检测故障,并且只有健康检查用于检测故障的结束。最后一种方法涉及集中报告:一个中央监控代理会定期向所有负载均衡器更新所有组件的状态。这为所有组件提供了基础设施的全局视图,尽管有时准确性或响应性较低。它最适合拥有许多负载均衡器和许多服务器的环境。L7 负载均衡器还面临另一个挑战,称为粘性或持久性。原则是它们通常必须将来自同一来源(例如最终用户)的多个后续请求或连接定向到同一目标。最著名的例子是在线商店的购物车。如果每次点击都会导致新连接,则用户必须始终被发送到持有其购物车的服务器。内容感知使得在请求中更容易找到某些元素来识别要将其发送到的服务器,但这并不总是足够。例如,如果将源地址用作选择服务器的键,则可以使用基于哈希的算法,并且给定 IP 地址将根据其数量除以可用服务器数量而始终发送到同一服务器。但是,如果一台服务器失败,结果就会改变,所有用户都会突然被发送到另一台服务器并丢失他们的购物车。解决此问题的方案是记住所选目标,以便每次看到相同的访问者时,无论可用服务器的数量如何,都会将其定向到同一服务器。信息可以存储在负载均衡器的内存中,在这种情况下,如果它不是独立的,则可能需要将其复制到其他负载均衡器,或者可以将其存储在客户端的内存中,使用各种方法,只要客户端能够每次请求都提供此信息(cookie 插入、重定向到子域等)。此机制提供了不依赖于不稳定或不均匀分布的信息(如源 IP 地址)的额外好处。事实上,这是采用 L7 负载均衡器而不是 L4 负载均衡器的最强原因。为了提取诸如 cookie、主机头字段、URL 或其他任何内容的信息,负载均衡器可能需要解密 SSL/TLS 流量,甚至可能在将其传递给服务器时重新加密。这项昂贵的任务解释了为什么在某些高流量基础设施中,有时会有很多负载均衡器。由于 L7 负载均衡器可能对流量执行许多复杂的操作(解密、解析、修改、匹配 cookie、决定发送到哪个服务器等),它确实可能导致一些问题,并且经常会被指责是许多它仅暴露的问题的根源。通常会发现服务器不稳定,周期性地出现和消失,或者对于 Web 服务器,它们提供带有硬编码链接的页面,迫使客户端直接连接到特定服务器而不经过负载均衡器,或者它们在高负载下响应缓慢导致超时。这就是为什么日志记录是 L7 负载均衡的一个极其重要的方面。一旦报告了问题,就必须弄清楚负载均衡器是否做出了错误的决定,如果是,为什么它会这样,以便不再发生。
HAProxy 写成“HAProxy”以指代产品,写成“haproxy”以指代可执行程序、软件包或进程。然而,两者通常都用于这两个目的,并且读作 H-A-Proxy。很早以前,“haproxy”代表“high availability proxy”,并且这个名字被写成两个独立的单词,尽管现在它只代表“HAProxy”。

3.1. 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 监狱内并放弃其权限,因此一旦启动,它不会执行任何文件系统访问。因此,它无法被转变为 Web 服务器。有优秀的开源软件可用于此,例如 Apache 或 Nginx,HAProxy 可以安装在它们前面以提供负载均衡和高可用性。- 基于数据包的负载均衡器:它不会看到 IP 数据包或 UDP 数据报,也不会执行 NAT,更不用说 DSR。这些是较低层的任务。一些基于内核的组件,如 IPVS(Linux Virtual Server)已经做得很好,并且与 HAProxy 完美互补。

3.2. HAProxy 的工作原理

HAProxy 是一个单线程、事件驱动、非阻塞引擎,结合了非常快的 I/O 层和基于优先级的调度器。由于其设计目标是转发数据,因此其架构经过优化,以最少的操作尽可能快地移动数据。因此,它实现了分层模型,在每个级别都提供旁路机制,确保数据在不需要时不会到达更高级别。大部分处理在内核中进行,HAProxy 通过提供一些提示或避免在它认为可以稍后分组的操作来尽最大努力帮助内核尽可能快地完成工作。结果,典型的数字显示,在 TCP 或 HTTP 关闭模式下,HAProxy 占用的处理时间为 15%,而内核占用的处理时间为 85%,在 HTTP 长连接模式下,HAProxy 占用的处理时间约为 30%,而内核占用的处理时间为 70%。一个进程可以运行多个代理实例;据报道,单个进程中多达 300,000 个不同的代理配置可以正常运行。因此,通常不需要为所有实例启动多个进程。可以使 HAProxy 在多个进程上运行,但这有一些限制。一般来说,在 HTTP 关闭或 TCP 模式下没有意义,因为内核侧在某些操作(如 connect())下扩展性不佳。它在 HTTP 长连接模式下扩展性非常好,但单个进程可达到的性能通常会比一般需求高出一个数量级。然而,当用作 SSL 卸载器时,它是有意义的,并且此功能在多进程模式下得到了很好的支持。HAProxy 只需要 haproxy 可执行文件和一个配置文件即可运行。对于日志记录,强烈建议配置一个适当的 syslog 守护进程和日志轮转。配置文件在启动前被解析,然后 HAProxy 尝试绑定所有监听套接字,如果任何一个失败则拒绝启动。在此之后,它就无法再失败了。这意味着没有运行时失败,并且如果它接受启动,它将一直工作直到被停止。一旦 HAProxy 启动,它只会做 3 件事:- 处理传入连接;- 定期检查服务器状态(称为健康检查);- 与其他 haproxy 节点交换信息。处理传入连接是迄今为止最复杂的任务,因为它取决于许多配置可能性,但可以将其总结为以下 9 个步骤:- 从属于称为“frontend”的配置实体的监听套接字接受传入连接,该实体引用一个或多个监听地址;- 对这些连接应用前端特定的处理规则,这可能导致阻塞它们、修改某些报头或拦截它们以执行某些内部小程序,例如统计页面或 CLI;- 将这些传入连接传递给另一个代表服务器场(称为“backend”)的配置实体,该实体包含服务器列表和该服务器场的负载均衡策略;- 对这些连接应用后端特定的处理规则;- 根据负载均衡策略决定将连接转发到哪个服务器;- 对响应数据应用后端特定的处理规则;- 对响应数据应用前端特定的处理规则;- 发出日志以详细报告发生的情况;- 在 HTTP 中,返回到第二步等待新请求,否则关闭连接。前端和后端有时被视为半代理,因为它们只关注端到端连接的一侧;前端只关心客户端,而后端只关心服务器。HAProxy 还支持全代理,全代理是前端和后端的联合。当需要 HTTP 处理时,配置通常会拆分为前端和后端,因为它们打开了许多可能性,因为任何前端都可以将连接传递给任何后端。对于仅 TCP 的代理,使用前端和后端很少有益处,并且使用全代理可以使配置更具可读性。

3.3. 基本功能

本节将列举 HAProxy 实现的许多功能,其中一些是任何现代负载均衡器通常期望的,而另一些则是 HAProxy 架构的直接优势。更高级的功能将在下一节中详细介绍。

3.3.1. 基本功能:代理

代理是指通过两个独立连接在客户端和服务器之间传输数据的操作。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

3.3.2. 基本功能:SSL

HAProxy 的 SSL 堆栈被认为是功能最强大的之一,根据 Google 工程师的说法(http://istlsfastyet.com/)。最常用的功能使其相当完善,包括:- 基于 SNI 的多站点托管,站点数量无限制且专注于性能。已知至少有一个部署运行了 50,000 个域名及其各自的证书;- 对通配符证书的支持减少了对许多证书的需求;- 基于证书的客户端身份验证,具有配置失败策略,无法呈现有效证书。例如,这允许呈现不同的服务器场来重新生成客户端证书;- 后端服务器的身份验证确保后端服务器是真实的,而不是中间人;- 与后端服务器的身份验证允许后端服务器知道连接到它的是预期的 haproxy 节点;- TLS NPN 和 ALPN 扩展使得能够可靠地卸载 SPDY/HTTP2 连接并将它们以明文形式传递给后端服务器;- OCSP stapling 进一步减少首次页面加载时间,方法是在客户端请求证书状态请求时内联传递 OCSP 响应;- 动态记录大小调整同时提供高性能和低延迟,并通过允许浏览器在数据包仍在传输过程中开始获取新对象来显著减少页面加载时间;- 永久访问所有相关的 SSL/TLS 层信息,用于日志记录、访问控制、报告等。这些元素可以嵌入到 HTTP 报头中,甚至作为 PROXY 协议扩展,以便被卸载的服务器能够获得如果在 SSL 终止本身执行时所拥有的所有信息。- 检测、记录和阻止某些已知的攻击,即使在易受攻击的 SSL 库上,例如影响 OpenSSL 某些版本的 Heartbleed 攻击。- 支持无状态会话恢复(RFC 5077 TLS Ticket 扩展)。TLS 票证可以从 CLI 更新,这为它们提供了实现完美前向保密的方法,通过频繁轮换票证。

3.3.3. 基本功能:监控

HAProxy 非常注重可用性。因此,它关心服务器的状态,并向其他网络组件报告自身的状态:- 服务器状态使用每个服务器的参数持续监控。这确保了到服务器的路径对于常规流量是可操作的;- 健康检查支持上/下转换的两个滞后,以防止状态抖动;- 检查可以发送到不同的地址/端口/协议:这使得检查一个被认为是多个服务的代表性服务变得容易,例如 HTTP+HTTPS 服务器的 HTTPS 端口;- 服务器可以跟踪其他服务器并同时失效:这确保了托管多个服务的服务器可以原子地失效,并且没有人会被发送到部分失效的服务器;- 可以在服务器上部署代理来监控负载和健康状况:服务器可能对报告其负载、运行状态、管理状态感兴趣,这独立于健康检查可以看到的内容。通过在服务器上运行一个简单的代理,除了验证整个路径的健康检查外,还可以考虑服务器自身对自身健康的看法;- 提供各种检查方法:TCP 连接、HTTP 请求、SMTP hello、SSL hello、LDAP、SQL、Redis、send/expect 脚本,所有这些都可以使用/不使用 SSL;- 状态更改会在日志和统计页面中通知,并附带失败原因(例如,检测到失败时收到的 HTTP 响应)。在发生此类更改时,还可以将电子邮件发送到可配置的地址;- 服务器状态也在统计界面上报告,并可用于做出路由决策,以便根据其大小和/或健康状况(例如,城际链路丢失)将流量发送到不同的服务器场;- HAProxy 可以使用健康检查请求将信息传递给服务器,例如它们的名称、权重、服务器场中的其他服务器数量等,以便服务器可以根据这些知识调整其响应和决策(例如,推迟备份以保留更多 CPU);- 服务器可以使用健康检查来报告比简单开关更详细的状态(例如,我想停止,请停止发送新访客);- HAProxy 本身可以向外部组件(如路由器或其他负载均衡器)报告其状态,从而能够构建非常完整的多路径和多层基础设施。

3.3.4. 基本功能:高可用性

就像任何严肃的负载均衡器一样,HAProxy 非常注重可用性,以确保最佳的全局服务连续性:- 只使用有效的服务器;其他服务器会自动从负载均衡场中移除;但在某些条件下仍然可以强制使用它们;- 支持优雅关闭,以便可以在不影响任何连接的情况下将服务器从场中移除;- 当活动服务器出现故障时,会自动使用备份服务器并替换它们,以便在可能的情况下不会丢失会话。这还允许构建多个路径来访问同一服务器(例如,多个接口);- 当农场中过多的服务器出现故障时,能够返回农场的全局失败状态。这与监控能力相结合,使得上游组件可以选择另一个 LB 节点来提供给定服务;- 无状态设计易于构建集群:HAProxy 在设计上尽最大努力确保最高的服务连续性,而无需存储在故障事件中可能丢失的信息。这确保了接管过程尽可能无缝;- 与标准的 VRRP 守护进程 keepalived 集成良好:HAProxy 轻松地将自身状态告知 keepalived,并能很好地处理浮动虚拟 IP 地址。注意:仅在基于集群的解决方案(Heartbeat 等)上使用 IP 冗余协议(VRRP/CARP),因为它们提供最快、最无缝、最可靠的切换。

3.3.5. 基本功能:负载均衡

HAProxy 提供了一套相当完整的负载均衡功能,其中大部分不幸的是在许多其他负载均衡产品中都无法获得:- 支持不少于 9 种负载均衡算法,其中一些应用于输入数据,提供了无限的可能性。最常见的算法是轮询(对于短连接,依次选择每个服务器)、最少连接(对于长连接,选择连接数最少的服务器中最近最少使用的服务器)、源(对于 SSL 场或终端服务器场,服务器直接依赖于客户端的源地址)、URI(对于 HTTP 缓存,服务器直接依赖于 HTTP URI)、hdr(服务器直接依赖于特定 HTTP 报头字段的内容)、first(对于寿命短的虚拟机,所有连接都打包到尽可能小的服务器子集上,以便未使用的服务器可以断电);- 所有上述算法都支持每个服务器的权重,因此可以容纳场中的不同服务器代,或者将一小部分流量定向到特定服务器(调试模式,运行下一版本软件等);- 轮询、最少连接和一致性哈希支持动态权重;这允许从 CLI 甚至由服务器上运行的代理实时修改服务器权重;- 动态权重支持的地方支持慢启动;这允许服务器逐步承担流量。这对于需要运行时编译类的脆弱应用程序服务器以及需要填充缓存才能满负荷运行的冷缓存非常重要;- 哈希可以应用于各种元素,如客户端源地址、URL 组件、查询字符串元素、报头字段值、POST 参数、RDP cookie;- 一致性哈希在添加或删除服务器时保护服务器场免受大规模重新分配。这在大型缓存场中非常重要,并且允许使用慢启动来填充冷缓存;- 许多内部指标,如每个服务器、每个后端的连接数、后端可用连接槽的数量等,使得构建非常高级的负载均衡策略成为可能。

3.3.6. 基本功能:粘性(Stickiness)

没有粘性,应用程序负载均衡将毫无用处。HAProxy 提供了一套相当全面的可能性,可以在服务器添加/删除、上下线循环等各种事件中将访问者保持在同一服务器上,并且一些方法被设计为能够抵抗多个负载均衡节点之间的距离,因为它们不需要任何复制:- 如果需要,粘性信息可以从不同地方单独匹配和学习。例如,JSESSIONID cookie 可以在 cookie 和 URL 中同时匹配。最多可以同时学习 8 个并行源,每个源可能指向不同的粘性表;- 粘性信息可以来自请求或响应中可见的任何内容,包括源地址、TCP 有效负载偏移和长度、HTTP 查询字符串元素、报头字段值、cookie 等。- 粘性表以多主模式在所有节点之间复制;- 常用的元素,如 SSL-ID 或 RDP cookie(用于 TSE 场),可以直接访问以方便操作;- 所有粘性规则都可以通过 ACLs 动态条件化;- 可以决定不粘性到某些服务器,例如备份服务器,这样当标称服务器回来时,它会自动重新承担负载。这在多路径环境中经常使用;- 在 HTTP 中,通常倾向于不学习任何东西,而是操作一个专门用于粘性的 cookie。为此,可以检测、重写、插入或添加前缀以让客户端记住分配了哪个服务器;- 服务器可能会决定在注销时更改或清除粘性 cookie,这样离开的访问者就会自动从服务器解绑;- 使用基于 ACL 的规则,还可以选择性地忽略或强制粘性,无论服务器的状态如何;结合高级健康检查,这有助于管理员在将服务器展示给全世界之前验证他们安装的服务器是否正常运行;- 一种创新的机制,用于设置 cookie 的最大空闲时间和持续时间,确保粘性可以在永不关闭的设备(智能手机、电视、家用电器)上平滑停止,而无需将它们存储在持久存储上;- 多个服务器条目可以共享相同的粘性键,这样在多路径环境中,当一条路径失效时,粘性就不会丢失;- soft-stop 确保只有具有粘性信息的用户将继续到达他们被分配到的服务器,但新用户将不会去那里。

3.3.7. 基本功能:信息采样与转换

HAProxy 支持使用一套广泛的“采样获取函数”来采样信息。其原理是提取称为样本的信息片段,供即时使用。这可用于粘性会话、构建条件、在日志中生成信息或丰富 HTTP 标头。样本可以从各种来源获取:- 常量:整数、字符串、IP 地址、二进制块;- 进程:日期、环境变量、服务器/前端/后端/进程状态、字节/连接计数/速率、队列长度、随机生成器等;- 变量:每个会话、每个请求、每个响应变量;- 客户端连接:源和目标地址及端口,以及所有相关的统计计数器;- SSL 客户端会话:协议、版本、算法、密码套件、密钥大小、会话 ID,所有客户端和服务器证书字段、证书序列号、SNI、ALPN、NPN,客户端对某些扩展的支持;- 请求和响应缓冲区内容:偏移量/长度的任意有效负载、数据长度、RDP cookie、SSL Hello 类型解码、TLS SNI 解码;- HTTP(请求和响应):方法、URI、路径、查询字符串参数、状态码、标头值、位置标头值、cookie、捕获、身份验证、正文元素;然后,样本可以通过一系列称为“转换器”的操作进行转换。转换器会消耗一个样本并生成一个新的样本,可能类型完全不同。例如,一个转换器可以只返回输入字符串的整数长度,或者可以将字符串转换为大写。可以在最终使用之前,按任意顺序将任意数量的转换器应用于一个样本。在所有可用的样本转换器中,以下是最常用的:- 算术和逻辑运算符:它们使得对输入数据进行高级计算成为可能,例如计算比率、百分比或简单地从一个单位转换为另一个单位;- IP 地址掩码在需要按较大网络对某些地址进行分组时很有用;- 数据表示:URL 解码、base64、十六进制、JSON 字符串、哈希;- 字符串转换:从固定位置、固定长度提取子字符串,围绕某些分隔符提取特定字段,提取特定单词,更改大小写,应用基于正则表达式的替换;- 日期转换:转换为 HTTP 日期格式,将本地时间转换为 UTC 并反之,添加或删除偏移量;- 在粘性表中查找条目以查找统计信息或分配的服务器;- 从文件进行基于映射的键值转换(主要用于地理位置)。

3.3.8. 基本功能:映射 (Maps)

映射是一种强大的转换器类型,它通过在启动时将一个两列文件加载到内存中,然后从第一列查找每个输入样本,如果找到条目,则返回第二列中的相应模式,否则返回默认值。输出信息也是一个样本,它可以经历其他转换,包括其他映射查找。映射最常用于将客户端的 IP 地址转换为 AS 号或国家代码,因为它们支持网络地址的最长匹配,但它们可以用于各种其他目的。它们的部分优势在于它们可以从 CLI 或通过其他样本的某些操作进行动态更新,从而使它们能够存储和检索后续访问之间的信息。另一个优势来自基于二进制树的索引,这使得它们即使包含数十万个条目也极其快速,从而使地理位置的设置非常便宜且容易。

3.3.9. 基本功能:ACL 和条件

HAProxy 中的大多数操作都可以有条件地执行。条件是通过使用逻辑运算符(AND、OR、NOT)组合多个 ACL 来构建的。每个 ACL 是一系列基于以下元素的测试:- 用于检索要测试元素的样本获取方法;- 用于转换元素的(可选)一系列转换器;- 要匹配的模式列表;- 指示如何将模式与样本进行比较的匹配方法。例如,样本可以从 HTTP “Host”标头中获取,然后可以将其转换为小写,然后使用正则表达式匹配方法与多个正则表达式模式进行匹配。从技术上讲,ACL 是基于与映射相同的核心构建的,它们共享完全相同的内部结构、模式匹配方法和性能。唯一的实际区别是,它们不返回样本,而只返回“找到”或“未找到”。在使用方面,ACL 模式可以在配置文件中内联声明,不需要自己的文件。ACL 可以命名以便于使用或使配置易于理解。命名的 ACL 可以多次声明,它将依次评估所有定义,直到有一个匹配。提供了大约 13 种不同的模式匹配方法,其中包括 IP 地址掩码、整数范围、子字符串、正则表达式。它们像函数一样工作,就像任何编程语言一样,只评估需要的部分,因此当涉及 OR 的条件已经为真时,就不会评估下一个条件,同样,当涉及 AND 的条件已经为假时,也不会评估条件的其余部分。声明的 ACL 数量没有实际限制,并且提供了一些常用的 ACL。然而,经验表明,使用大量命名 ACL 的设置非常难以排除故障,并且有时使用内联匿名 ACL 会更容易,因为它在正在分析的范围之外需要的引用更少。

3.3.10. 基本功能:内容切换

HAProxy 实现了一种称为基于内容的切换的机制。其原理是连接或请求到达前端,然后处理此请求或连接携带的信息,此时可以编写基于 ACL 的条件,利用这些信息来决定哪个后端将处理该请求。因此,流量根据请求的内容被定向到一个或另一个后端。最常见的例子是使用 Host 标头和/或路径中的元素(子目录或文件名扩展名)来决定 HTTP 请求是针对静态对象还是应用程序,并将静态对象流量路由到由快速轻量级服务器组成的后端,并将所有剩余流量路由到更复杂的应用程序服务器,从而构成一个精细的虚拟托管解决方案。这对于使多种技术共存作为一个更全局的解决方案非常方便。内容切换的另一个用例是根据各种标准使用不同的负载均衡算法。缓存可以使用 URI 哈希,而应用程序将使用轮询。最后但同样重要的是,它允许多个客户使用一小部分共享资源,方法是强制执行每个后端(因此每个客户连接限制)。内容切换规则的可扩展性非常好,尽管其性能可能取决于 ACL 的数量和复杂性。但也可以编写动态内容切换规则,其中样本值直接转换为后端名称,而无需使用 ACL。据报道,此类配置至少在生产环境中支持 300,000 个后端。

3.3.11. 基本功能:粘性表 (Stick-tables)

粘性表通常用于存储粘性信息,即保留用户被定向到的服务器的引用。键是与访问者关联的标识符(其源地址、连接的 SSL ID、HTTP 或 RDP cookie、从 URL 或有效负载中提取的客户编号等),存储的值是服务器的标识符。粘性表可以使用 3 种不同类型的样本作为键:整数、字符串和地址。每个代理只能引用一个粘性表,并且在任何地方都使用代理名称进行标识。最多可以并行跟踪 8 个键。服务器标识符在请求或响应处理过程中提交,一旦键和服务器都已知。粘性表的内容可以以主动-主动模式与其他称为“对等节点”的 HAProxy 节点以及重新加载操作期间的新进程进行复制,以便所有负载均衡节点共享相同的信息并在客户端请求分布到多个节点时做出相同的路由决策。由于粘性表是基于识别客户端的内容进行索引的,因此它们通常也用于存储额外信息,例如每个客户端的统计信息。额外统计信息需要额外的空间,并且需要显式声明。可存储的统计信息类型包括输入和输出带宽、并发连接数、一段时间内的连接速率和计数、错误量和频率、某些特定标签和计数器等。为了支持在不强制粘附到给定服务器的情况下存储此类信息,实现了一种特殊的“跟踪”功能,允许同时跟踪不同表中的最多 3 个键,而不管粘性规则如何。每个存储的统计信息都可以从 CLI 中搜索、转储和清除,并增加了实时故障排除功能。虽然此机制可用于识别返回访问者或根据良好或不良行为调整提供的服务质量,但它主要用于对抗服务滥用,更广泛地用于 DDoS,因为它允许构建复杂的模型以高处理速度检测某些不良行为。

3.3.12. 基本功能:格式化字符串

在很多地方,HAProxy 需要操作字符串,例如日志、重定向、添加标头等等。为了提供最大的灵活性,引入了格式化字符串的概念,最初是为了日志记录的目的,这也解释了为什么它仍然被称为“log-format”。这些字符串包含转义字符,允许将各种动态数据(包括变量和样本获取表达式)引入字符串中,甚至可以在结果转换为字符串时调整编码(例如,添加引号)。这提供了一种强大的方式来构建标头内容或自定义日志行。此外,为了保持构建最常见字符串的简单性,提供了大约 50 个特殊标签作为日志中常用信息的快捷方式。

3.3.13. 基本功能:HTTP 重写和重定向

将负载均衡器安装在未为此设计的应用程序前面可能是一项艰巨的任务,如果没有合适的工具。在这种情况下,最常要求的操作之一是调整请求和响应标头,以使负载均衡器看起来像源服务器并修复硬编码的信息。这包括更改请求中的路径(强烈不建议)、修改 Host 标头字段、修改重定向的 Location 响应标头字段、修改 cookie 的路径和域属性等。此外,一些服务器有时会过于冗长,并在响应中泄露过多信息,使其更容易受到定向攻击。虽然理论上清理这些信息不是负载均衡器的作用,但实际上它位于基础设施中的最佳位置,可以保证所有内容都得到清理。同样,有时负载均衡器将不得不拦截某些请求并用重定向到新目标 URL 来响应。虽然有些人倾向于混淆重定向和重写,但这是两个完全不同的概念,因为重写使客户端和服务器看到不同的内容(并在正在访问的页面位置上不一致),而重定向要求客户端访问新的 URL,以便它看到与服务器相同的位置。为了做到这一点,HAProxy 支持各种重写和重定向的可能性,其中包括:- 请求和响应中基于正则表达式的 URL 和标头重写。正则表达式是修改标头值最常用的工具,因为它们易于操作且易于理解;- 标头也可以根据格式化字符串进行附加、删除或替换,以便可以传递信息(例如,客户端 TLS 算法和密码套件);- HTTP 重定向可以使用任何 3xx 代码重定向到相对、绝对或完全动态(格式化字符串)的 URI;- HTTP 重定向还支持一些额外选项,例如设置或清除特定 cookie、丢弃查询字符串、在缺少时追加斜杠等;- 所有操作都支持基于 ACL 的条件;

3.3.14. 基本功能:服务器保护

HAProxy 在最大化服务可用性方面做了很多工作,并且为此付出了巨大努力来保护服务器免受过载和攻击。第一个也是最重要的点是,只有完整且有效的请求才会被转发到服务器。最初的原因是 HAProxy 需要找到协议元素以保持与字节流同步,第二个原因是直到请求完成,才知道某些元素是否会改变其语义。这带来的直接好处是服务器不会暴露给无效或不完整的请求。这是针对慢速攻击(slowloris attacks)的一种非常有效的防护措施,这些攻击对 HAProxy 几乎没有影响。另一个重要的点是 HAProxy 包含用于存储请求和响应的缓冲区,并且通过仅在请求完成后才将其发送到服务器,并从本地网络非常快速地读取整个响应,服务器端连接的使用时间非常短,这尽可能地节省了服务器资源。这直接扩展到 HAProxy 可以人为地限制到服务器的并发连接数或未完成请求数,这保证了即使服务器在流量高峰期持续以 100% 的容量运行,它也不会过载。所有过多的请求将被排队,以便在释放一个槽时进行处理。最终,这种巨大的资源节省通常能确保更好的服务器响应时间,以至于实际速度比服务器过载时更快。排队的请求可以重新分发到其他服务器,甚至可以在客户端中止时在队列中中止,这也保护了服务器免受“重新加载效果”,即访问者在加载缓慢的页面上每次点击“重新加载”通常都会触发新请求,并使服务器保持在过载状态。慢启动机制还可以防止正在重新启动的服务器在启动完成或编译某些类时处理高流量。关于协议级别的保护,可以放宽 HTTP 解析器以接受非标准但无害的请求或响应,甚至可以修复它们。这使得可以使用一些有问题的应用程序,同时开发修复程序。同时,冒犯性的消息会被完全捕获,并附有详细报告,帮助开发人员发现应用程序中的问题。最危险的协议违规行为会被正确检测和处理并修复。例如,具有两个 Content-length 标头的格式错误的请求或响应,如果值完全相同则会被修复,如果不同则被拒绝,因为这会成为安全问题。协议检查不仅限于 HTTP,也适用于 TLS 或 RDP 等其他协议。当检测到协议违规或攻击时,有各种选项可以响应用户,例如返回常见的“HTTP 400 bad request”,通过 TCP 重置关闭连接,或在长时间延迟后伪造错误(“tarpit”)以混淆攻击者。所有这些都有助于通过阻止冒犯性客户端继续进行维护成本非常高的攻击来保护服务器。HAProxy 还提供了一些更高级的选项来防止意外的数据泄露和会话交叉。它不仅可以记录可疑的服务器响应,还可以记录并选择性地阻止可能影响给定访问者保密性的响应。其中一个例子是在可缓存的响应中出现可缓存的 cookie,这可能导致中间缓存将其提供给另一个访问者,从而导致意外的会话共享。

3.3.15. 基本功能:日志记录

日志记录是负载均衡器的一项极其重要的功能,首先是因为负载均衡器经常被错误地指责导致其揭示的问题,其次是因为它位于基础设施的关键位置,所有正常和异常活动都需要在此进行分析并与其他组件相关联。HAProxy 提供非常详细的日志,具有毫秒级的精度和确切的连接接受时间,可以在防火墙日志中进行搜索(例如,用于 NAT 相关性)。默认情况下,TCP 和 HTTP 日志相当详细,包含排除故障所需的一切,例如源 IP 地址和端口、前端、后端、服务器、计时器(请求接收持续时间、队列持续时间、连接设置时间、响应标头时间、数据传输时间)、全局进程状态、连接计数、队列状态、重试计数、详细的粘性操作和断开连接原因、具有安全输出编码的标头捕获。然后可以扩展或替换此格式以包含任何采样数据、变量、捕获,从而产生非常详细的信息。例如,可以记录客户端的累积请求数或访问的不同 URL 数。可以使用标准 ACL 按请求调整日志级别,因此可以自动静默某些被视为垃圾的日志,而在部分流量发生异常行为时发出警告(例如,来自某个源地址的 URL 或 HTTP 错误过多)。还发出管理日志及其自身的级别,以告知服务器的丢失或恢复等情况。每个前端和后端可以使用多个独立的日志输出,这有利于多租户。日志首选通过 UDP 发送,可能是 JSON 编码的,并在可配置的行长度后截断,以保证交付。

3.3.16. 基本功能:统计

HAProxy 提供一个基于 Web 的统计报告界面,具有身份验证、安全级别和范围功能。因此,可以为每个托管的客户提供他自己的页面,只显示他自己的实例。这个页面可以位于常规网站的一个隐藏 URL 部分,这样就不需要打开新的端口。这个页面还可以报告其他 HAProxy 节点的可用性,以便可以一目了然地发现一切是否按预期工作。视图是综合性的,可以访问许多详细信息(例如错误原因、最后访问和最后更改持续时间等),这些信息也可以作为 CSV 表格访问,其他工具可以导入该表格来绘制图表。该页面可以自动刷新,用作大型显示器上的监控页面。在管理模式下,该页面还允许更改服务器状态,以方便维护操作。

3.4. 高级功能

3.4.1. 高级功能:管理

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 的分支也可以在一定程度上实现);- halog(来自最新 HAProxy 版本):这是日志分析工具,它以极高的速度(每秒 1 到 2 GB)解析本地 TCP 和 HTTP 日志,并提取有用的信息和统计信息,例如每个 URL、每个源地址的请求,按响应时间或错误率排序的 URL,终止代码等。它被设计为部署在生产服务器上以帮助排除实时问题,因此它必须在那里准备好使用;- tcpdump:强烈建议使用它来获取排除日志中显示的问题所需的网络跟踪。在某个时候,应用程序和 HAProxy 的分析会产生分歧,而网络跟踪是判断谁对谁错的唯一方法。通过 tcpdump 检测网络堆栈和虚拟化程序的错误也相当常见;- strace:它是 tcpdump 的伴侣。它将报告 HAProxy 实际看到的内容,并有助于区分操作系统负责的问题和 HAProxy 负责的问题。当怀疑 HAProxy 中存在错误时,通常会要求使用 strace;

3.4.2. 高级功能:系统特定能力

根据 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 本身已提供保护。

3.4.3. 高级功能:脚本

HAProxy 可以通过 Lua 嵌入式语言进行构建,这为复杂的请求或响应操作、路由决策、统计处理等领域开辟了广泛的新可能性。使用 Lua 甚至可以建立到其他服务器的并行连接以交换信息。这样,例如,开发身份验证系统就成为可能(尽管很复杂)。有关如何使用 Lua 的更多信息,请参阅文件“doc/lua-api/index.rst”中的文档。

3.5. 规模估算

典型的 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 NIC,运行 Linux 内核 3.10、HAProxy 1.6 和 OpenSSL 1.0.2。HAProxy 在单个专用 CPU 核心上作为一个进程运行,另外两个核心专用于网络中断:- 对于 256 kB 或更大的对象,最大网络带宽为 20 Gbps(明文),对于 41kB 或更大的对象,为 10 Gbps;- 使用 AES256-GCM 密码套件和大型对象,TLS 流量为 4.6 Gbps;- 每秒 83000 个 TCP 连接(从客户端到服务器);- 每秒 82000 个 HTTP 连接(从客户端到服务器);- 在服务器关闭模式下(与客户端保持长连接,与服务器关闭)每秒 97000 个 HTTP 请求;- 在端到端长连接模式下每秒 243000 个 HTTP 请求;- 每秒 300000 个过滤后的 TCP 连接(防 DDoS);- 在长连接的持久 TLS 连接上,每秒 160000 个 HTTPS 请求;- 使用 TLS 恢复连接,每秒 13100 个 HTTPS 请求;- 使用与 RSA2048 重新协商的 TLS 连接,每秒 1300 个 HTTPS 连接;- 每 GB RAM 20000 个并发饱和连接(包括系统缓冲区所需的内存);通过仔细调优可以做得更好,但这个结果很容易实现。- 每 GB RAM 大约 8000 个并发 TLS 连接(仅客户端),包括系统缓冲区所需的内存;- 每 GB RAM 大约 5000 个并发端到端 TLS 连接(双边),包括系统缓冲区所需的内存;因此,一个需要牢记的经验法则是,请求速率在 TLS 长连接和 TLS 恢复之间,以及在 TLS 恢复和 TLS 重新协商之间除以 10,而在 HTTP 长连接和 HTTP 关闭之间仅除以 3。另一个好的经验法则是,要记住,具有 AES 指令的高频核心每个核心可以处理大约 5 Gbps 的 AES-GCM。拥有更多核心很少有帮助(除了 TLS),并且由于频率较低,甚至会适得其反。总的来说,少量高频核心更好。另一个好的经验法则是,在同一服务器上,HAProxy 将能够饱和:- 大约 5-10 个静态文件服务器或缓存代理;- 大约 100 个防病毒代理;- 大约 100-1000 个应用程序服务器,具体取决于所使用的技术。

3.6. 如何获取 HAProxy

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 Ports。这些系统通常提供长期维护的版本,这些版本不一定包含官方版本的所有修复,但至少包含关键修复。对于大多数不寻求高级配置、只想轻松更新的用户来说,这通常是一个不错的选择;- 来自 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 相关,也在此处提及。

4.1. Apache HTTP 服务器

Apache 是事实上的标准 HTTP 服务器。它是一个非常完整且模块化的项目,支持文件服务和动态内容。它可以作为某些应用程序服务器的前端。它甚至可以代理请求和缓存响应。在所有这些用例中,通常需要一个前端负载均衡器。Apache 可以以各种模式工作,有些比其他模式更重。某些模块仍然需要更重的预派(pre-forked)模型,这将阻止 Apache 很好地扩展到大量连接。在这种情况下,HAProxy 可以通过将每个服务器的连接数限制到安全值来提供巨大的帮助,并将显着加快服务器速度并保留其资源,使应用程序更好地使用这些资源。Apache 可以通过使用“mod_rpaf”扩展从 X-Forwarded-For 标头中提取客户端的地址。如果 HAProxy 的配置中指定了“option forwardfor”,它将自动提供此标头。当暴露给互联网时,HAProxy 也可能为 Apache 提供良好的保护,它可以更好地抵抗各种类型的 DoS 攻击。

4.2. NGINX

NGINX 是事实上的第二标准 HTTP 服务器。与 Apache 一样,它涵盖了广泛的功能。NGINX 基于与 HAProxy 类似的模型构建,因此它在处理数万个并发连接方面没有问题。当用作某些应用程序(例如使用 PHP FPM)的网关时,设置一些前端连接限制以减少 PHP 应用程序的负载通常是有益的。HAProxy 在这里既可以作为常规负载均衡器,也可以作为流量调节器,通过缓解 PHP 的拥塞来加速 PHP。此外,由于两个产品都受益于其事件驱动架构,因此 CPU 使用量很少,因此它们通常可以轻松地安装在同一系统上。NGINX 实现了 HAProxy 的 PROXY 协议,因此 HAProxy 可以轻松地将客户端的连接信息传递给 NGINX,从而使应用程序获得所有相关信息。一些基准测试也表明,对于大型静态文件服务,在 NGINX 前面实现 HAProxy 的一致性哈希是有益的,通过优化操作系统的缓存命中率,缓存命中率基本上乘以服务器节点的数量。

4.3. Varnish

Varnish 是一个智能的缓存反向代理,可能最好被描述为一个 Web 应用程序加速器。Varnish 不实现 SSL/TLS,并希望将其所有 CPU 周期专注于它最擅长的事情。Varnish 也实现了 HAProxy 的 PROXY 协议,因此 HAProxy 可以非常容易地部署在 Varnish 前端,作为 SSL 卸载器和负载均衡器,并向其传递所有相关的客户端信息。此外,当服务器提供了压缩对象时,Varnish 天然支持从缓存中解压缩,但它本身不进行压缩。当后端服务器未实现压缩时,HAProxy 可以用于压缩传出的数据,尽管在负载均衡器上进行压缩通常不是一个好主意,除非流量很低。当在多个节点上构建大型缓存集群时,HAProxy 可以利用一致性 URL 哈希来智能地将负载分配到缓存节点,并避免缓存重复,从而使总缓存大小等于所有缓存节点的总和。

4.4. 替代品

Linux Virtual Server (LVS 或 IPVS) 是包含在 Linux 内核中的第 4 层负载均衡器。它在数据包级别工作,处理 TCP 和 UDP。在大多数情况下,它更多的是一种补充而不是替代,因为它完全没有第 7 层知识。Pound 是另一个知名的负载均衡器。它比 HAProxy 简单得多,功能也少得多,但对于许多非常基本的设置,两者都可以使用。其作者一直将代码可审计性放在首位,并希望保持功能集低。其基于线程的架构在连接数很高的情况下扩展性较差,但它是一个好产品。Pen 是一个相当轻量级的负载均衡器。它支持 SSL,通过固定大小的客户端 IP 地址表来维护持久性。它支持面向数据包的模式,允许它在一定程度上支持直接服务器返回和 UDP。它适用于小负载(持久性表只有 2048 个条目)。NGINX 在一定程度上也可以进行负载均衡,尽管这显然不是它的主要功能。生产流量用于检测服务器故障,负载均衡算法更有限,粘性(stickiness)非常有限。但在它已经存在的一些简单的部署场景中,它是有意义的。好消息是,由于它与 HAProxy 集成得非常好,当其限制被达到时,稍后添加 HAProxy 没有什么问题。Varnish 也对后端服务器进行一些负载均衡,并支持真实的健康检查。然而,它不实现粘性,所以就像 NGINX 一样,只要不需要粘性,就可以作为起点。同样,由于 HAProxy 和 Varnish 集成得很好,稍后将它添加到组合中以补充功能集是很容易的。


HAProxy 1.7.14 – 入门指南
,