本文档不提供任何配置方面的帮助或提示,但它解释了在哪里可以找到相关文档。下面的概述旨在帮助您按名称搜索章节并在文档中导航。致文档贡献者:本文档的格式为每行 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:这是 HAProxy 和许多第三方产品实现的 PROXY 协议的实际规范。 - README:如何从源代码构建 HAProxy。
负载均衡旨在聚合多个组件,以实现在无需最终用户干预且可扩展的情况下,总处理能力超过每个组件的单独能力。这导致在组件执行一次操作的时间内,可以同时执行更多操作。然而,单个操作一次仍将在单个组件上执行,并且不会比没有负载均衡更快。它始终需要至少与可用组件一样多的操作以及高效的负载均衡机制,才能充分利用所有组件并充分受益于负载均衡。一个很好的例子是高速公路上的车道数量,它允许在相同的时间范围内通过尽可能多的汽车,而无需增加它们各自的速度。负载均衡的示例: - 多处理器系统中的进程调度 - 链路负载均衡(例如 EtherChannel、Bonding) - IP 地址负载均衡(例如 ECMP、DNS 轮询) - 服务器负载均衡(通过负载均衡器) 执行负载均衡操作的机制或组件称为负载均衡器。在 Web 环境中,这些组件被称为“网络负载均衡器”,更常见的是“负载均衡器”,因为这项活动是迄今为止最著名的负载均衡案例。负载均衡器可以作用于: - 链路层:这称为链路负载均衡,它包括选择将数据包发送到哪个网络链路; - 网络层:这称为网络负载均衡,它包括选择一系列数据包将遵循的路由; - 服务器层:这称为服务器负载均衡,它包括决定哪个服务器将处理连接或请求。存在两种不同的技术,它们解决不同的需求,尽管有些重叠。在每种情况下,重要的是要记住,负载均衡包括将流量从其自然流中分流,并且这样做总是需要最少的注意,以保持所有路由决策之间所需的一致性水平。第一种是在数据包层面操作,或多或少地单独处理数据包。输入和输出数据包之间存在一对一的关系,因此可以使用常规网络嗅探器跟踪负载均衡器两侧的流量。这种技术可以非常便宜且速度极快。它通常在硬件(ASIC)中实现,可以达到线速,例如执行 ECMP 的交换机。通常是无状态的,它也可以是有状态的(考虑数据包所属的会话,称为第 4 层负载均衡或 L4),如果数据包未被修改,可能支持 DSR(直接服务器返回,无需再次通过 LB),但几乎不提供内容感知。这种技术非常适合网络级负载均衡,尽管它有时也用于高速下的非常基本的服务器负载均衡。第二种是在会话内容上操作。它要求将输入流重新组装并作为一个整体进行处理。内容可以被修改,输出流被分割成新的数据包。因此,它通常由代理执行,它们通常被称为第 7 层负载均衡器或 L7。这意味着两侧存在两个不同的连接,并且输入和输出数据包的大小和数量之间没有关系。客户端和服务器不需要使用相同的协议(例如 IPv4 与 IPv6,明文与 SSL)。操作始终是有状态的,并且返回流量必须通过负载均衡器。额外的处理会带来成本,因此并非总能达到线速,尤其是在小数据包的情况下。另一方面,它提供了广泛的可能性,并且通常通过纯软件实现,即使嵌入到硬件设备中也是如此。这种技术非常适合服务器负载均衡。基于数据包的负载均衡器通常以直通模式部署,因此它们安装在流量的正常路径上,并根据配置进行分流。返回流量不一定通过负载均衡器。为了将流量导向正确的目的地,可能会对网络目标地址进行一些修改。在这种情况下,返回流量必须通过负载均衡器。如果路由无法实现这一点,负载均衡器还可以将其自身的 IP 地址替换为数据包的源地址,以强制返回流量通过它。基于代理的负载均衡器作为具有自己 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 监狱中并放弃其权限,因此一旦启动,它将不再执行任何文件系统访问。因此,它不能变成 Web 服务器。有许多优秀的开源软件用于此,例如 Apache 或 Nginx,HAProxy 可以安装在它们的前面,以提供负载均衡和高可用性。 - 基于数据包的负载均衡器:它不会查看 IP 数据包或 UDP 数据报,不会执行 NAT,更不会执行 DSR。这些是较低层的任务。一些基于内核的组件,例如 IPVS(Linux 虚拟服务器)已经做得很好,并且与 HAProxy 完美互补。
HAProxy 是一个单线程、事件驱动、非阻塞引擎,结合了极快的 I/O 层和基于优先级的调度器。由于其设计目标是数据转发,因此其架构经过优化,可以以最少的操作尽可能快地移动数据。因此,它实现了分层模型,在每个级别提供旁路机制,确保数据除非必要不会到达更高层。大部分处理是在内核中进行的,HAProxy 尽力通过提供一些提示或避免某些操作(当它猜测它们以后可以分组时)来帮助内核尽快完成工作。因此,在 TCP 或 HTTP 关闭模式下,典型的数字显示 HAProxy 占处理时间的 15%,而内核占 85%;在 HTTP keep-alive 模式下,HAProxy 占 30%,而内核占 70%。一个进程可以运行多个代理实例;据报道,单个进程中运行多达 30 万个不同代理的配置运行良好。因此,通常无需为所有实例启动多个进程。HAProxy 可以运行在多个进程上,但有一些限制。通常在 HTTP 关闭或 TCP 模式下没有意义,因为内核侧在某些操作(例如 connect())上扩展性不佳。它在 HTTP keep-alive 模式下扩展性很好,但单个进程可以实现的性能通常比普通需求高一个数量级。但是,当用作 SSL 卸载器时,它确实有意义,并且此功能在多进程模式下得到了很好的支持。HAProxy 只需要 haproxy 可执行文件和配置文件即可运行。为了日志记录,强烈建议配置适当的 syslog 守护程序和日志轮换。配置文件在启动前进行解析,然后 HAProxy 尝试绑定所有监听套接字,如果任何操作失败,则拒绝启动。在此之后,它不能再失败。这意味着没有运行时故障,如果它接受启动,它将一直工作直到停止。一旦 HAProxy 启动,它只做 3 件事: - 处理传入连接; - 定期检查服务器状态(称为健康检查); - 与其他 haproxy 节点交换信息。处理传入连接是迄今为止最复杂的任务,因为它依赖于大量的配置可能性,但可以总结为以下 9 个步骤: - 接受来自属于配置实体(称为“前端”)的监听套接字的传入连接,该实体引用一个或多个监听地址; - 对这些连接应用前端特定的处理规则,这可能导致阻止它们、修改某些头部或拦截它们以执行一些内部小程序,例如统计页面或 CLI; - 将这些传入连接传递给另一个配置实体,该实体代表一个服务器场,称为“后端”,其中包含服务器列表和此服务器场的负载均衡策略; - 对这些连接应用后端特定的处理规则; - 根据负载均衡策略决定将连接转发到哪个服务器; - 对响应数据应用后端特定的处理规则; - 对响应数据应用前端特定的处理规则; - 发出日志以详细报告发生了什么; - 在 HTTP 中,循环回第二步以等待新请求,否则关闭连接。前端和后端有时被认为是半代理,因为它们只查看端到端连接的一侧;前端只关心客户端,而后端只关心服务器。HAProxy 还支持全代理,它正是前端和后端的结合。当需要 HTTP 处理时,配置通常会分为前端和后端,因为它们提供了很多可能性,因为任何前端都可以将连接传递给任何后端。对于仅 TCP 代理,使用前端和后端很少带来好处,并且使用全代理的配置可能更具可读性。
本节将列举 HAProxy 实现的许多功能,其中一些是任何现代负载均衡器通常期望的,而另一些则是 HAProxy 架构的直接优势。更高级的功能将在下一节中详细介绍。
代理是将数据在客户端和服务器之间通过两个独立的连接进行传输的行为。HAProxy 在代理和连接管理方面支持以下基本功能: - 为服务器提供干净的连接,以保护它们免受任何客户端缺陷或攻击; - 监听多个 IP 地址和/或端口,甚至端口范围; - 透明接受:拦截针对任何任意 IP 地址(甚至不属于本地系统)的流量; - 服务器端口无需与监听端口相关联,甚至可以通过固定偏移量进行转换(对范围有用); - 透明连接:在连接到服务器时,如果需要,伪造客户端(或任何)IP 地址; - 在多站点 LB 中为服务器提供可靠的返回 IP 地址; - 通过缓冲区和可能的短寿命连接卸载服务器,以减少其并发连接数和内存占用; - 优化 TCP 堆栈(例如 SACK)、拥塞控制,并减少 RTT 影响; - 支持两侧不同的协议族(例如 IPv4/IPv6/Unix); - 超时强制:HAProxy 支持多个超时级别,具体取决于连接所处的阶段,以便死客户端或服务器,或攻击者不会被授予资源太长时间; - 协议验证:检查 HTTP、SSL 或负载,并拒绝无效的协议元素,除非指示无论如何都接受它们; - 策略强制:确保只转发允许的内容; - 传入和传出连接都可以限制在某些网络命名空间(仅限 Linux),从而轻松构建跨容器、多租户负载均衡器; - PROXY 协议即使对于非 HTTP 流量,也会向服务器呈现客户端的 IP 地址。这是 HAProxy 的一个扩展,现在已被许多第三方产品采用,至少在撰写本文时有以下产品: - 客户端:haproxy、stud、stunnel、exaproxy、ELB、squid - 服务器:haproxy、stud、postfix、exim、nginx、squid、node.js、varnish
根据谷歌工程师的说法(http://istlsfastyet.com/),HAProxy 的 SSL 堆栈被认为是功能最丰富的之一。使其相当完整的常用功能包括: - 基于 SNI 的多主机托管,对站点数量没有限制,并专注于性能。已知至少有一个部署运行着 50000 个域名及其各自的证书; - 支持通配符证书减少了对许多证书的需求; - 基于证书的客户端认证,对未能提供有效证书的情况可配置策略。这允许为客户端提供不同的服务器场以重新生成客户端证书; - 后端服务器认证确保后端服务器是真实的,而不是中间人; - 与后端服务器的认证让后端服务器知道连接到它的确实是预期的 haproxy 节点; - TLS NPN 和 ALPN 扩展使得可靠地卸载 SPDY/HTTP2 连接并将它们以明文形式传递给后端服务器成为可能; - OCSP stapling 通过在客户端请求证书状态请求时提供内联 OCSP 响应,进一步减少了首次页面加载时间; - 动态记录大小兼具高性能和低延迟,并通过让浏览器在数据包仍在传输中时开始获取新对象,显著减少了页面加载时间; - 永久访问所有相关的 SSL/TLS 层信息,用于日志记录、访问控制、报告等。这些元素可以嵌入到 HTTP 头部或作为 PROXY 协议扩展,以便卸载的服务器获得它在自行执行 SSL 终止时会获得的所有信息。 - 检测、记录和阻止某些已知攻击,即使在易受攻击的 SSL 库上,例如影响某些 OpenSSL 版本的 Heartbleed 攻击。 - 支持无状态会话恢复(RFC 5077 TLS 票据扩展)。TLS 票据可以从 CLI 更新,这为它们提供了通过频繁轮换票据来实现完美前向保密的方法。
HAProxy 非常注重可用性。因此,它关心服务器状态,并向其他网络组件报告其自身状态: - 使用每服务器参数持续监控服务器状态。这确保了通往服务器的路径对常规流量是可操作的; - 健康检查支持上下转换的两个滞后,以防止状态抖动; - 检查可以发送到不同的地址/端口/协议:这使得检查一个被认为是多个服务代表的单个服务变得容易,例如 HTTP+HTTPS 服务器的 HTTPS 端口。 - 服务器可以跟踪其他服务器并同时宕机:这确保了托管多个服务的服务器可以原子地失败,并且没有人会被发送到部分失败的服务器; - 代理可以部署在服务器上以监控负载和健康状况:服务器可能希望独立于健康检查所能看到的内容报告其负载、操作状态、管理状态。通过在服务器上运行一个简单的代理,除了验证整个路径的健康检查之外,还可以考虑服务器对自身健康状况的看法; - 提供各种检查方法:TCP 连接、HTTP 请求、SMTP hello、SSL hello、LDAP、SQL、Redis、发送/预期脚本,所有这些都带/不带 SSL; - 状态更改会在日志和统计页面中通知,并附带失败原因(例如,在检测到失败时收到的 HTTP 响应)。在此类更改发生时,也可以向可配置的地址发送电子邮件; - 服务器状态也会在统计接口上报告,并可用于做出路由决策,以便根据服务器的大小和/或健康状况将流量发送到不同的服务器群(例如,数据中心间链路的丢失); - HAProxy 可以使用健康检查请求将信息传递给服务器,例如它们的名称、权重、服务器群中其他服务器的数量等,以便服务器可以根据这些知识调整其响应和决策(例如,推迟备份以保留更多 CPU 可用); - 服务器可以使用健康检查报告比开/关更详细的状态(例如,我希望停止,请停止发送新访客); - HAProxy 本身可以向外部组件(例如路由器或其他负载均衡器)报告其状态,从而构建非常完整的、多路径和多层的基础设施。
就像任何严肃的负载均衡器一样,HAProxy 非常注重可用性,以确保最佳的全球服务连续性: - 仅使用有效服务器;其他服务器会自动从负载均衡服务器群中逐出;在某些条件下,仍然可以强制使用它们; - 支持优雅停机,以便在不影响任何连接的情况下将服务器从服务器群中取出; - 当活动服务器宕机时,会自动使用备用服务器并替换它们,以便在可能的情况下不会丢失会话。这还允许构建多条路径来访问同一服务器(例如,多个接口); - 当太多服务器宕机时,能够为服务器群返回全局失败状态。这与监控功能相结合,使得上游组件可以选择不同的 LB 节点来提供给定服务; - 无状态设计使得构建集群变得容易:HAProxy 的设计宗旨是尽力确保最高的服务器连续性,而无需存储在发生故障时可能会丢失的信息。这确保了接管尽可能无缝; - 与标准 VRRP 守护进程 keepalived 良好集成:HAProxy 轻松地将自身状态告知 keepalived,并与浮动虚拟 IP 地址配合良好。注意:仅在基于集群的解决方案(Heartbeat 等)上使用 IP 冗余协议(VRRP/CARP),因为它们提供了最快、最无缝、最可靠的切换。
HAProxy 提供了一套相当完整的负载均衡功能,其中大部分在许多其他负载均衡产品中都不可用: - 支持不少于 9 种负载均衡算法,其中一些适用于输入数据,提供无限的可能性。最常见的有轮询(适用于短连接,依次选择每个服务器)、最少连接(适用于长连接,选择连接数最少的服务器中最近使用最少的服务器)、源(适用于 SSL 服务器群或终端服务器群,服务器直接取决于客户端的源地址)、URI(适用于 HTTP 缓存,服务器直接取决于 HTTP URI)、hdr(服务器直接取决于特定 HTTP 头部字段的内容)、first(适用于短命虚拟机,所有连接都集中在尽可能小的服务器子集上,以便未使用的服务器可以关机); - 上述所有算法都支持每服务器权重,以便在服务器群中适应不同代际的服务器,或将一小部分流量导向特定服务器(调试模式,运行下一版本软件等); - 轮询、最少连接和一致性哈希支持动态权重;这允许从 CLI 或甚至由在服务器上运行的代理实时修改服务器权重; - 只要支持动态权重,就支持慢启动;这允许服务器逐渐接管流量。这对于需要运行时编译类以及需要在使用前填充的冷缓存的脆弱应用程序服务器来说是一个重要功能; - 哈希可以应用于各种元素,例如客户端源地址、URL 组件、查询字符串元素、头部字段值、POST 参数、RDP cookie; - 一致性哈希保护服务器群在添加或删除服务器时免受大规模重新分配。这在大型缓存服务器群中非常重要,它允许使用慢启动来重新填充冷缓存; - 许多内部指标,例如每服务器、每后端的连接数,后端中可用连接槽的数量等,使得构建非常高级的负载均衡策略成为可能。
没有粘性,应用负载均衡将毫无用处。HAProxy 提供了一套相当全面的功能,可以在各种事件(如服务器添加/删除、宕机/启动循环)中将访问者保持在同一服务器上,并且某些方法旨在抵抗多个负载均衡节点之间的距离,因为它们不需要任何复制: - 如果需要,可以从不同的位置单独匹配和学习粘性信息。例如,JSESSIONID cookie 可以在 cookie 中和 URL 中同时匹配。最多可以同时学习 8 个并行源,每个源可能指向不同的粘性表; - 粘性信息可以来自请求或响应中可见的任何内容,包括源地址、TCP 负载偏移量和长度、HTTP 查询字符串元素、头部字段值、cookie 等。 - 粘性表在多主模式下在所有节点之间复制; - 常用元素,如 SSL-ID 或 RDP cookie(用于 TSE 场),可直接访问以方便操作; - 所有粘性规则都可以通过 ACL 进行动态条件控制; - 可以决定不粘附到某些服务器,例如备用服务器,这样当标称服务器恢复时,它会自动接管负载。这通常用于多路径环境中; - 在 HTTP 中,通常 предпочましい 不学习任何东西,而是操作一个专门用于粘性的 cookie。为此,可以检测、重写、插入或为这样的 cookie 添加前缀,以让客户端记住分配了哪个服务器; - 服务器可以决定在注销时更改或清除粘性 cookie,以便离开的访问者自动与服务器解绑; - 使用基于 ACL 的规则,还可以选择性地忽略或强制执行粘性,无论服务器的状态如何;结合高级健康检查,这有助于管理员在向全世界展示服务器之前验证他们正在安装的服务器是否正常运行; - 一种创新的机制,用于设置 cookie 的最大空闲时间和持续时间,确保在永不关闭的设备(智能手机、电视、家用电器)上可以平稳地停止粘性,而无需将其存储在持久存储中; - 多个服务器条目可以共享相同的粘性键,这样在多路径环境中当一个路径宕机时,粘性不会丢失; - 软停止确保只有具有粘性信息的用户才能继续访问他们已被分配到的服务器,但不会有新用户访问该服务器。
HAProxy 支持使用一套广泛的“样本提取函数”进行信息采样。其原理是提取称为样本的信息片段,以供即时使用。这用于粘性、构建条件、在日志中生成信息或丰富 HTTP 头部。样本可以从各种来源获取: - 常量:整数、字符串、IP 地址、二进制块; - 进程:日期、环境变量、服务器/前端/后端/进程状态、字节/连接计数/速率、队列长度、随机生成器,... - 变量:每会话、每请求、每响应变量; - 客户端连接:源和目标地址和端口,以及所有相关的统计计数器; - SSL 客户端会话:协议、版本、算法、密码、密钥大小、会话 ID、所有客户端和服务器证书字段、证书序列、SNI、ALPN、NPN、客户端对某些扩展的支持; - 请求和响应缓冲区内容:偏移量/长度处的任意负载、数据长度、RDP cookie、SSL hello 类型解码、TLS SNI 解码; - HTTP(请求和响应):方法、URI、路径、查询字符串参数、状态码、头部值、位置头部值、cookie、捕获、认证、正文元素;然后,样本可以通过一系列称为“转换器”的运算符进行一些转换。转换器消耗一个样本并生成一个新样本,可能是完全不同的类型。例如,转换器可以用于只返回输入字符串的整数长度,或者可以将字符串转换为大写。在最终使用之前,可以对样本串联应用任意数量的转换器。在所有可用的样本转换器中,以下是使用最常见的: - 算术和逻辑运算符:它们可以对输入数据执行高级计算,例如计算比率、百分比或简单地从一个单位转换为另一个单位; - IP 地址掩码在需要按更大网络分组某些地址时很有用; - 数据表示:URL 解码、base64、hex、JSON 字符串、哈希; - 字符串转换:在固定位置、固定长度提取子字符串,围绕特定分隔符提取特定字段,提取特定单词,更改大小写,应用基于正则表达式的替换; - 日期转换:转换为 HTTP 日期格式,将本地时间转换为 UTC,反之亦然,添加或删除偏移量; - 在粘性表中查找条目以查找统计数据或分配的服务器; - 基于文件的键到值映射转换(主要用于地理定位)。
映射是一种强大的转换器类型,它通过在启动时将一个两列文件加载到内存中,然后从第一列查找每个输入样本,如果找到条目,则返回第二列中的相应模式,否则返回默认值。输出信息也是一个样本,它可以经历其他转换,包括其他映射查找。映射最常用于将客户端的 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。据报道,此类配置在生产环境中至少有 30 万个后端时运行良好。
粘性表通常用于存储粘性信息,即保留对特定访问者被导向的服务器的引用。键是与访问者关联的标识符(其源地址、连接的 SSL ID、HTTP 或 RDP cookie、从 URL 或有效负载中提取的客户编号等),存储的值是服务器的标识符。粘性表可以使用 3 种不同类型的样本作为键:整数、字符串和地址。在代理中只能引用一个粘性表,它在任何地方都用代理名称指定。最多可以并行跟踪 8 个键。一旦键和服务器都已知,服务器标识符将在请求或响应处理期间提交。粘性表内容可以在主动-主动模式下与已知为“对等体”的其他 HAProxy 节点以及在重新加载操作期间与新进程进行复制,以便所有负载均衡节点共享相同的信息,并且如果客户端请求分布在多个节点上,则做出相同的路由决策。由于粘性表是根据识别客户端的依据进行索引的,因此它们通常也用于存储额外信息,例如每客户端统计数据。额外统计数据会占用一些额外空间,需要明确声明。可以存储的统计数据类型包括输入和输出带宽、并发连接数、一段时间内的连接速率和计数、错误数量和频率、一些特定标签和计数器等。为了支持保留此类信息而不必强制粘附到给定服务器,实现了一种特殊的“跟踪”功能,允许同时跟踪来自不同表的最多 3 个并发键,无论粘性规则如何。每个存储的统计数据都可以从 CLI 搜索、转储和清除,并增加了实时故障排除能力。虽然此机制可用于优待回访者或根据良好或不良行为调整提供的服务质量,但它主要用于对抗服务滥用和更普遍的 DDoS,因为它允许构建复杂模型以高速检测某些不良行为。
在很多地方,HAProxy 需要操作字符串,例如日志、重定向、添加标头等等。为了提供最大的灵活性,引入了格式化字符串的概念,最初是为了日志记录的目的,这也解释了为什么它仍然被称为“log-format”。这些字符串包含转义字符,允许将各种动态数据(包括变量和样本获取表达式)引入字符串中,甚至可以在结果转换为字符串时调整编码(例如,添加引号)。这提供了一种强大的方式来构建标头内容或自定义日志行。此外,为了保持构建最常见字符串的简单性,提供了大约 50 个特殊标签作为日志中常用信息的快捷方式。
在从未为此目的设计的应用程序前面安装负载均衡器可能是一项具有挑战性的任务,如果没有适当的工具。在这种情况下,最常请求的操作之一是调整请求和响应头部,以使负载均衡器显示为源服务器并修复硬编码信息。这涉及到更改请求中的路径(强烈建议不要这样做)、修改 Host 头部字段、修改用于重定向的 Location 响应头部字段、修改 cookie 的 path 和 domain 属性等等。还存在一些服务器过于冗长,倾向于在响应中泄露过多信息,使其更容易受到有针对性的攻击。虽然从理论上讲,这不是负载均衡器的职责,但实际上它位于基础设施中最好的位置,以确保所有内容都得到清理。同样,有时负载均衡器需要拦截一些请求并以重定向到新目标 URL 进行响应。虽然有些人倾向于混淆重定向和重写,但这是两个完全不同的概念,因为重写使客户端和服务器看到不同的东西(并且在访问页面的位置上存在分歧),而重定向要求客户端访问新的 URL,以便它看到与服务器相同的位置。为了做到这一点,HAProxy 支持各种重写和重定向的可能性,其中包括: - 基于正则表达式的 URL 和头部在请求和响应中的重写。正则表达式是修改头部值最常用的工具,因为它们易于操作且易于理解; - 头部也可以根据格式化字符串进行附加、删除或替换,以便传递信息(例如客户端 TLS 算法和密码); - HTTP 重定向可以使用任何 3xx 代码到相对、绝对或完全动态(格式化字符串)的 URI; - HTTP 重定向还支持一些额外选项,例如设置或清除特定 cookie、删除查询字符串、如果缺少则附加斜杠等等; - 所有操作都支持基于 ACL 的条件;
HAProxy 为最大限度地提高服务可用性做了大量工作,为此它付出了巨大的努力来保护服务器免受过载和攻击。第一点也是最重要的一点是,只有完整且有效的请求才会转发到服务器。最初的原因是 HAProxy 需要找到它需要保持与字节流同步的协议元素,第二个原因是,在请求完成之前,无法知道某些元素是否会改变其语义。直接的好处是服务器不会暴露于无效或不完整的请求。这是对 slowloris 攻击的非常有效的保护,此类攻击对 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 和映射中的条目,更新 TLS 共享秘密,实时对任意前端应用连接限制和速率限制(在共享主机环境中很有用),并禁用特定前端以释放监听端口(当禁止白天操作但仍需要修复时很有用)。对于强制要求 SNMP 的环境,至少存在两个代理,一个随 HAProxy 源代码提供并依赖于 Net-SNMP Perl 模块。另一个随商业软件包提供,不需要 Perl。两者在覆盖范围上大致相同。通常建议在部署 HAProxy 的机器上安装 4 个实用程序: - socat(用于连接 CLI,尽管某些 netcat 分支也能在一定程度上实现); - 最新 HAProxy 版本的 halog:这是日志分析工具,它以极快的速度(每秒 1 到 2 GB)解析原生 TCP 和 HTTP 日志,并提取有用的信息和统计数据,例如按 URL、按源地址的请求数、按响应时间或错误率排序的 URL、终止代码等。它旨在部署在生产服务器上,以帮助解决实时问题,因此它必须在那里随时可用; - tcpdump:强烈建议使用此工具来获取故障排除日志中可见问题所需的网络跟踪。应用程序和 haproxy 的分析总会有分歧,网络跟踪是判断谁对谁错的唯一方法。通过 tcpdump 检测网络堆栈和虚拟化程序中的错误也相当常见; - 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 是否保护自己免受其影响。
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 内核 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,服务器关闭); - 端到端 Keep-Alive 模式下每秒 243000 个 HTTP 请求; - 每秒 300000 个过滤的 TCP 连接(抗 DDoS); - 持久 TLS 连接上 Keep-Alive 模式下每秒 160000 个 HTTPS 请求; - 使用 TLS 恢复连接时每秒 13100 个 HTTPS 请求; - 使用 RSA2048 重新协商的 TLS 连接时每秒 1300 个 HTTPS 连接; - 每 GB 内存并发饱和连接约 20000 个,包括系统缓冲区所需的内存;通过仔细调优可以做得更好,但这个结果很容易实现。 - 每 GB 内存并发 TLS 连接(仅客户端)约 8000 个,包括系统缓冲区所需的内存; - 每 GB 内存并发端到端 TLS 连接(两侧)约 5000 个,包括系统缓冲区所需的内存;因此,一个值得记住的好经验法则是,请求速率在 TLS Keep-Alive 和 TLS 恢复之间,以及在 TLS 恢复和 TLS 重新协商之间相差 10 倍,而在 HTTP Keep-Alive 和 HTTP 关闭之间仅相差 3 倍。另一个好经验法则是,记住一个带有 AES 指令的高频核心可以达到每核心约 5 Gbps 的 AES-GCM 速度。拥有更多核心很少有帮助(除了 TLS),甚至由于频率较低而适得其反。通常,少量高频核心更好。另一个好经验法则是,在同一服务器上,HAProxy 将能够饱和: - 大约 5-10 个静态文件服务器或缓存代理; - 大约 100 个防病毒代理; - 大约 100-1000 个应用程序服务器,具体取决于所使用的技术。
HAProxy 是一个受 GPLv2 许可证保护的开源项目,这意味着在请求时(尤其是在进行任何修改时)必须提供源代码,所有人都可以重新分发它。HAProxy 作为名为“master”或“mainline”的主开发分支不断演进,一旦代码被认为稳定,就会从中派生出新的分支。许多网站自愿在生产环境中运行一些开发分支,要么是为了参与项目,要么是因为他们需要最新的功能,他们的反馈对于修复错误和判断所开发版本的整体质量和稳定性非常有价值。当代码足够稳定时创建的新分支构成了稳定版本,通常会维护数年,因此即使您没有使用最新版本,也没有必要紧急迁移到更新的分支。一旦发布稳定分支,它可能只会收到错误修复,并且很少有次要功能更新,以方便用户使用。所有进入稳定分支的修复都必须来自主分支。这保证了升级后不会丢失任何修复。因此,如果您修复了一个错误,请针对主分支而不是稳定分支制作补丁。您甚至可能会发现它已经被修复了。此过程还确保稳定分支中的回归极为罕见,因此始终没有理由不升级到当前分支中的最新版本。分支用两个点分隔的数字编号,例如“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 版本将以以下格式显示(<分支>-<最新提交>-<修订版>):HA-Proxy version 1.5.0-994126-357 2015/07/02 - 对于特定于系统的软件包,您必须与供应商的软件包存储库或更新系统进行核对,以确保您的系统仍然受支持,并且仍然为您的分支提供修复。对于来自 haproxy.org 的社区版本,只需访问该网站,验证您的分支状态并将最新版本与您的版本进行比较,以查看您是否使用的是最新版本。如果不是,您可以升级。如果您的分支不再维护,您肯定已经非常落后,必须考虑升级到更近的分支(在这样做时请仔细阅读 README)。HAProxy 必须根据其来源进行更新。通常它遵循系统供应商升级软件包的方式。如果它是从源代码获取的,请在提取源代码后阅读源代码目录中的 README 文件,并按照适用于您的操作系统的说明进行操作。
HAProxy 与下面列出的一些产品集成得相当好,因此即使它们不直接与 HAProxy 相关,也在此处提及。
Apache 是事实上的标准 HTTP 服务器。它是一个非常完整和模块化的项目,支持文件服务和动态内容。它可以作为某些应用服务器的前端。它甚至可以代理请求和缓存响应。在所有这些用例中,通常需要一个前端负载均衡器。Apache 可以以各种模式工作,有些模式比其他模式更重。某些模块仍然需要更重的预分叉模型,这将阻止 Apache 在大量连接下良好扩展。在这种情况下,HAProxy 可以通过将每个服务器的连接限制强制为安全值来提供巨大的帮助,并将显著加快服务器速度并保留其资源,这些资源将更好地用于应用程序。Apache 可以使用“mod_rpaf”扩展从 X-Forwarded-For 标头中提取客户端地址。当其配置中指定“option forwardfor”时,HAProxy 将自动填充此标头。当暴露于互联网时,HAProxy 还可以为 Apache 提供良好的保护,它将更好地抵抗多种类型的 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 可以在一定程度上进行一些负载均衡,尽管这显然不是它的主要功能。生产流量用于检测服务器故障,负载均衡算法更加有限,并且粘性非常有限。但在一些已经存在 NGINX 的简单部署场景中,它可能是有意义的。好的一点是,由于它与 HAProxy 集成得非常好,因此当达到其限制时,以后再添加 HAProxy 也没有问题。Varnish 也对其后端服务器进行一些负载均衡,并且确实支持真实的健康检查。但是,它不实现粘性,因此就像 NGINX 一样,只要不需要粘性,这可能足以开始使用。同样,由于 HAProxy 和 Varnish 如此良好地集成在一起,因此以后很容易将其添加到组合中以补充功能集。