抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

译者:serchaofan

翻译主要借助翻译工具,并进行校对。

根据官方 18.14 与 18.15 文档 Starter Guide的翻译,并非完整翻译,且有的地方会有修改与删除。

快速介绍负载均衡和负载均衡器

负载均衡包括聚合多个组件,以便在每个组件的单独流量上实现总处理能力,而无需客户端用户的任何干预并且是可扩展的。这导致组件在仅执行一个操作所花费的时间内同时执行更多操作。 但是,单个操作仍然会一次在单个组件上执行,并且不会比没有负载均衡时更快。 它始终需要至少与可用组件一样多的操作和有效的负载均衡机制来充分利用所有组件并从负载均衡中充分受益。一个很好的例子是高速公路上的车道数量,不增加车辆速度而允许尽可能多的车辆在同一时间段内通过。

负载均衡的示例:

  • 多处理器系统中的进程调度
  • 链路负载均衡(例如 EtherChannel,Bonding)
  • IP 地址负载均衡(例如 ECMP,DNS round-robin)
  • 服务器负载均衡(通过负载均衡器)

执行负载均衡操作的机制或组件称为负载均衡器。 在 Web 环境中,这些组件称为“网络负载均衡器”,更常见的是“负载均衡器”,因为此说法是迄今为止负载均衡的最好示例。

负载均衡器可以起作用:

  • 在链路级别:这称为链路负载均衡,它包括选择发送数据包的网络链路
  • 在网络级别:这称为网络负载均衡,它包括选择一系列数据包将使用的路由
  • 在服务器级别:这称为服务器负载均衡,它包括决定哪个服务器将处理连接或请求

存在两种不同的技术并满足不同的需求,但有一些重叠。在每种情况下,重要的是要记住,负载均衡包括将流量从其自然流转移,并且这样做总是需要最少的维护,以维持所有路由决策之间所需的一致性水平。

第一个技术作用于数据包级别并且或多或少地单独处理数据包。 输入和输出数据包之间存在一对一的关系,因此可以使用常规网络嗅探器跟踪负载均衡器两侧的流量。这项技术非常便宜且速度极快。 它通常以硬件(ASIC)实现,能够达到线速(line rate),例如执行 ECMP 的交换机。 通常是无状态的,它也可以是有状态的(考虑一个数据包所属的会话并称为 layer4-LB 或 L4),如果数据包没有被修改,可以支持 DSR(直接服务器返回,不再通过 LB),但几乎不提供内容感知(content awareness)。 该技术非常适合网络级负载均衡,但有时用于高速的基本服务器负载均衡。

第二个技术作用于会话内容。 它要求输入流作为一个整体进行重组和处理。 可以修改内容,并且将输出流分段为新分组。出于这个原因,它通常由代理执行,它们通常被称为第 7 层负载均衡器或 L7。这意味着每一侧有两个不同的连接,并且输入和输出数据包大小与计数之间没有关系。客户端和服务器不需要使用相同的协议(例如 IPv4 与 IPv6,不加密与 SSL)。 操作始终是有状态的,返回流量必须通过负载均衡器。 额外的处理带来了成本,因此并不总是能够实现线速,特别是对于小数据包。 另一方面,它提供了广泛的可能性,并且通常通过纯软件实现,即使嵌入到硬件设备中也是如此。 该技术非常适合服务器负载均衡。

基于数据包的负载均衡器通常以直通模式(cut-though mode)部署,因此它们安装在流量的正常路径上,并根据配置进行转移。 返回的流量不一定通过负载均衡器。 可以对网络目的地址进行一些修改,以便将流量引导到适当的目的地。 在这种情况下,返回流量必须通过负载均衡器。如果路由不能实现这一点,则负载均衡器也可以用自己的路由替换数据包的源地址,强制返回流量通过它。

基于代理的负载均衡器部署为具有自己的 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”来指定产品,而“haproxy”被指定为可执行程序,软件包或进程。 然而,两者通常用于两种目的,并且发音为 H-A-Proxy。,很早以前,“haproxy”曾经代表“高可用性代理”,这个名字用两个单独的单词写成,但现在它只不过是“HAProxy”。

HAProxy 是什么与不是什么

HAProxy 是:

  • TCP 代理:它可以接受来自侦听套接字的 TCP 连接,连接到服务器并将这些套接字连接在一起,允许流量在两个方向上流动
  • HTTP 反向代理(在 HTTP 术语中称为“网关”):它将自身表示为服务器,通过侦听 TCP 套接字上接受的连接接收 HTTP 请求,并使用不同的连接将请求从这些连接传递到服务器。
  • SSL 终端/发起者/卸载程序(offloader):SSL / TLS 可用于来自客户端,到服务器的连接,甚至两个连接的连接。
  • TCP 规范化程序(normalizer):由于操作系统本地终止了连接,双方之间没有关系,因此无效数据包、标志组合、窗口通告(window advertisement)、序列号、不完整连接(SYN 泛洪)等异常流量不会被传递到另一边。 这可以保护脆弱的 TCP 栈免受协议攻击,并且还允许与客户端优化连接参数,而无需修改服务器的 TCP 栈设置。
  • HTTP 规范化程序:配置为处理 HTTP 流量时,仅传递有效的完整请求。 这可以防止许多基于协议的攻击。 另外,规范中存在容差的协议偏差是固定的,因此它们不会在服务器上引起问题(例如,多行头)。
  • HTTP 修复工具:它可以修改/修复/添加/删除/重写 URL 或任何请求或响应头。 这有助于解决复杂环境中的互操作性(interoperability)问题。
  • 基于内容的交换机:它可以根据请求中的任何元素来决定将请求或连接传递给哪个服务器。 因此,可以在同一端口上处理多个协议(例如,HTTP,HTTPS,SSH)。
  • 服务器负载均衡器:它可以对 TCP 连接和 HTTP 请求进行负载均衡。 在 TCP 模式下,对整个连接采取负载均衡决策。 在 HTTP 模式下,根据请求做出决定。
  • 流量调节器:它可以在不同点应用一些速率限制,保护服务器免受过载,根据内容调整流量优先级,甚至通过标记数据包将这些信息传递给较低层和外部网络组件。
  • 防止 DDoS 和服务滥用(service abuse):它可以维护每个 IP 地址,URL,cookie 等的大量统计信息,并检测何时发生滥用,然后采取措施(减慢违规行为,阻止它们,将它们发送到过时的内容 等)。
  • 网络故障排除的观察点:由于日志中报告的信息的精确性,它通常用于缩小网络相关问题的范围。
  • HTTP 压缩卸载程序:它可以压缩未被服务器压缩的响应,从而减少连接不良或使用高延迟移动网络的客户端的页面加载时间。

HAProxy 不是:

  • 显式 HTTP 代理,即浏览器用于访问互联网的代理。 有专门用于此任务的优秀开源软件,例如 Squid。 但是,HAProxy 可以部署在这样的代理之前,以提供负载均衡和高可用性。
  • 缓存代理:它将按原样返回从服务器收到的内容,不会干扰任何缓存策略。 有很好的开源软件可以完成这项任务,比如 Varnish。 HAProxy 可以部署在这样的缓存之前,通过智能负载均衡提供 SSL 卸载和可扩展性。
  • 数据清理程序:它不会修改请求体和响应体。
  • Web 服务器:在启动期间,它将自己隔离在 chroot jail 中并删除其权限,以便一旦启动它就不会执行任何单个文件系统访问。 因此,它无法转变为 Web 服务器。 有很好的开源软件,如 Apache 或 Nginx,HAProxy 可以部署在它们前端,以提供负载均衡和高可用性。
  • 基于数据包的负载均衡器:它不会看到 IP 数据包也不会看到 UDP 数据包,也不会执行 NAT 甚至更少的 DSR(动态源路由协议)。 这些是较低层的任务。 一些基于内核的组件(如 IPVS(Linux 虚拟服务器))已经很好地完成了这项工作并与 HAProxy 完美匹配。

HAProxy 如何工作

HAProxy 是一个单线程,事件驱动的非阻塞引擎,它将非常快的 I / O 层与基于优先级的调度程序相结合。 由于它的设计考虑了数据转发目标,因此其架构经过优化,可以尽可能快地以尽可能少的操作移动数据。 因此,它实现了一个分层模型,在每个级别提供旁路机制(bypass mechanisms),确保数据不会达到更高级别,除非需要。 大多数处理都是在内核中执行的,HAProxy 尽最大努力通过提供一些提示或者在猜测它们可以在以后分组时避免某些操作来尽可能快地帮助内核完成工作。 因此,典型数据显示,在 TCP 或 HTTP 关闭模式下,HAProxy 中花费的处理时间占 15%,而在内核占 85%,在 HTTP keep-alive 模式下,HAProxy 约占 30%,而内核占 70%。

单个进程可以运行许多代理实例。根据试验,单个进程中大到 300000 个不同代理的配置运行正常。 因此,通常不需要为所有实例启动多个进程。

可以使 HAProxy 在多个进程上运行,但它有一些限制。 一般来说,它在 HTTP 关闭或 TCP 模式下没有意义,因为内核端不能很好地扩展一些操作,如connect()。 它可以很好地扩展到 HTTP 的 keep-alive 模式,但是可以通过单个进程实现的性能通常比常见的需求高出一个数量级。 但是,当用作 SSL 卸载器(offloader)时,它确实有意义,并且在多进程模式中很好地支持此功能。

HAProxy 只需要运行 haproxy 可执行文件和配置文件。 对于日志记录,强烈建议使用正确配置的 syslog 守护程序并记录日志轮换。 在启动之前解析配置文件,然后 HAProxy 尝试绑定所有侦听套接字,并在任何失败时拒绝启动。做到这一点,它就不会运行失败了。 这意味着没有运行时故障,如果它接受启动,它将一直有效,直到它停止。

一旦 HAProxy 被启动,它会做三件事:

  • 处理传入的连接
  • 定期检查服务器状态(称为健康检查)
  • 与其他 haproxy 节点交换信息

处理传入连接是迄今为止最复杂的任务,因为它依赖于许多配置可能性,但它可以概括为以下 9 个步骤:

  1. 接受来自属于称为frontend的配置实体的侦听套接字的传入连接 ,引用一个或多个侦听地址
  2. 将特定于 frontend 的处理规则应用于这些可能导致阻塞它们,修改某些头或拦截它们以执行某些内部小程序(例如统计页面或 CLI)的连接
  3. 将这些传入连接传递给另一个表示称为backend的服务器池的配置实体,该服务器场包含服务器列表和此服务器池的负载均衡策略
  4. 将特定于后端的处理规则应用于这些连接
  5. 根据负载均衡策略决定将连接转发到哪个服务器
  6. 将特定于后端的处理规则应用于响应数据
  7. 将特定于前端的处理规则应用于响应数据
  8. 发出日志详细报告发生的事情
  9. 在 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

SSL

Google 的工程师(http://istlsfastyet.com/)认为HAProxy的SSL栈是最具特色的功能之一。 使其相当完整的最常用特性是:

  • 基于 SNI 的多主机,不限制站点数量并专注于性能。 至少有一个部署用于运行 50000 个域及其各自的证书
  • 对通配符证书(wildcard certificates)的支持减少了对许多证书的需求
  • 基于证书的客户端身份验证,如果无法提供有效证书,则使用可配置策略。例如,这允许不同的服务器池重新生成客户端证书
  • 后端服务器的身份验证确保后端服务器是真正的后端服务器而不是中间人
  • 使用后端服务器进行身份验证让后端服务器知道它实际上是连接到它的预期 haproxy 节点
  • TLS NPN 和 ALPN 扩展使得可以可靠地卸载 SPDY/HTTP2 连接并以明文形式将它们传递给后端服务器
  • 当客户端请求证书状态请求时,通过提供内联 OCSP 响应,OCSP 装订(stapling)进一步减少了首页加载时间
  • 动态记录大小调整可提供高性能和低延迟,并且当数据包仍处于运行状态时,允许浏览器开始获取新对象,从而显着缩短页面加载时间
  • 永久访问所有相关的 SSL/TLS 层信息,用于日志记录、访问控制、报告等。这些元素可以嵌入到 HTTP 报头中,甚至可以作为代理协议扩展,这样卸载的服务器就可以获得如果它自己执行 SSL 终止时会有的所有信息
  • 在易受攻击的 SSL 库上检测、记录和阻止某些已知攻击,例如影响 OpenSSL 某些版本的 Heartbleed 攻击
  • 支持无状态会话恢复(RFC 5077 TLS 故障单扩展)。可以从 CLI 更新 TLS 票证,通过频繁翻转(rotate)票证为他们提供实现 Perfect Forward Secrecy 的方法。

监控

HAProxy 非常关注可用性。 因此,它关心服务器状态,并将其自身状态报告给其他网络组件:

  • 使用每台服务器的参数持续监控服务器的状态。 这确保了服务器的路径可用于常规流量
  • 健康检查支持两个滞后(hysteresis)的上下转换,以防止状态振荡
  • 可以将检查发送到不同的地址/端口/协议:这样可以轻松检查被视为代表多个服务的单个服务,例如 HTTP + HTTPS 服务器的 HTTPS 端口。
  • 服务器可以跟踪其他服务器并同时关闭:这可确保托管多个服务的服务器可以原子方式失败,并且不会将任何人发送到部分故障的服务器
  • 可以在服务器上部署代理以监视负载和运行状况:服务器可能有兴趣报告其负载,运行状态,管理状态,而不管运行状况检查可以看到什么。
    通过在服务器上运行一个简单的代理,除了验证整个路径的运行状况检查外,还可以考虑服务器对自身运行状况的看法
  • 提供各种检查方法:TCP 连接,HTTP 请求,SMTP hello,SSL hello,LDAP,SQL,Redis,send /
    expect 脚本,所有有/无 SSL
  • 状态更改在日志和统计信息页面中以失败原因通知(例如,在检测到故障时收到的 HTTP 响应)。
    在发生此类更改时,也可以将电子邮件发送到可配置的地址
  • 服务器状态也在统计接口上报告,并且可用于做出路由决定,以便可以根据流量大小和/或健康状况(例如,丢失 DC 间链路)将流量发送到不同的服务器场。
  • HAProxy 可以使用运行状况检查请求将信息传递给服务器,例如其名称,重量,服务器场中其他服务器的数量等,以便服务器可以根据这些知识调整其响应和决策(例如,推迟备份以保持
    更多 CPU 可用)
  • 服务器可以使用健康检查报告更详细的状态,而不仅仅是打开/关闭(例如,我想停止,请停止发送新访问者)
  • HAProxy 本身可以将其状态报告给外部组件,例如路由器或其他负载均衡器,从而可以构建非常完整的多路径和多层基础架构。

高可用

就像任何负载均衡器一样,HAProxy 非常重视可用性,以确保最佳的全局服务持续性:

  • 仅使用有效的服务器,其他的被自动从负载均衡服务器群中剔除,在某些条件下,仍有可能强制使用它们
  • 支持优雅关闭,以便可以在不影响任何连接的情况下将服务器从服务器群中剔除
  • 当活跃服务器关闭时自动使用备份服务器并替换它们,以便在可能的情况下不会丢失会话。 这还允许构建多个路径以到达相同的服务器(例如,多个接口)
  • 当服务器过多时,能够返回服务器群的全局故障状态。 这与监视功能相结合,使上游组件可以为给定的服务选择不同的 LB 节点
  • 无状态设计使构建集群变得容易:通过设计,HAProxy 尽最大努力确保最高的服务持续性,而无需存储在发生故障时可能丢失的信息。 这确保了接管是最无缝的。
  • 与标准 VRRP 守护程序保持良好集成:HAProxy 告知 keepalived 其状态,并与浮动虚拟 IP 地址很好地对应。 注意:仅使用基于集群的解决方案(Heartbeat,…)的 IP 冗余协议(VRRP/CARP),因为它们是提供最快,最无缝和最可靠切换的解决方案。

负载均衡

HAProxy 提供了一套相当完整的负载均衡功能,其中大多数功能在许多其他负载均衡产品中是不支持的:

  • 支持不少于 9 种负载均衡算法,其中一些适用于输入数据,以提供无限的可能性列表。 最常见的是 round-robin(用于短连接,依次选择每个服务器),leastconn(用于长连接,选择最近最少使用的具有最低连接数的服务器),source(用于 SSL 服务器群或终端服务器群,服务器直接依赖于客户端的源地址),uri(对于 HTTP 缓存,服务器直接依赖于 HTTP URI),hdr(服务器直接依赖于特定 HTTP 头字段的内容),first(对于短期虚拟机,所有连接都打包在最小的服务器子集上,以便可以关闭未使用的服务器)

  • 以上所有算法都支持服务器权重,以便可以适应服务器群中不同的级别的服务器,或者将一小部分流量引导到特定服务器(调试模式,运行下一版本的软件等)

  • 支持动态权重的轮询、最小控制和一致哈希,这允许从 CLI 动态修改服务器权重,甚至允许服务器上运行的代理修改服务器权重

  • 只要支持动态权重,就支持慢启动,这允许服务器逐步获取流量。 这是脆弱的应用程序服务器的一个重要特性,它需要在运行时编译类以及需要在全速运行之前填满的冷缓存(cold caches)

  • 散列可以应用于各种元素,如客户端的源地址,URL 组件,查询字符串元素,报文头字段值,POST 参数,RDP cookie

  • 在服务器群中添加或删除服务器时,一致性哈希(consitent hashing)可保护服务器群免受大量重新分发的影响。 这在大型缓存群中非常重要,它允许使用慢启动来重新填充冷缓存

  • 许多内部指标,例如每个服务器、每个后端的连接数,后端中可用连接插槽的数量等,可以构建非常先进的负载均衡策略。

粘性

如果没有粘性(stickness),应用程序负载均衡将毫无用处。 HAProxy 提供了一套相当全面的可能性,可以将访问者维持在同一台服务器上,甚至可以跨越各种事件,例如服务器添加/删除,下线/上线周期,并且某些方法可以克服多个负载均衡节点之间的距离并不需要任何复制:

  • 如果需要,粘性信息可以单独匹配并从不同的地方学习。 例如,JSESSIONID cookie 可以在 cookie 和 URL 中匹配。 可以同时学习多达 8 个并行源,每个源可以指向不同的绑定表(stick-table)

  • 粘性信息可以来自请求或响应中可以看到的任何内容,包括源地址,TCP 有效负载偏移和长度,HTTP 查询字符串元素,报头字段值,cookie 等

  • 以多主方式在所有节点之间复制绑定表

  • 常用的元素,如 SSL-ID 或 RDP cookie(用于 TSE 群)可直接访问,以方便操作

  • 所有粘性规则都可以由 ACL 动态调节

  • 可以决定不绑定某些服务器,例如备份服务器。这样当名义上的(nominal)服务器返回集群时,它会自动恢复负载。 这通常用于多路径环境

  • 在 HTTP 中,通常不会学习任何东西,而是操纵专用于粘性的 cookie。 为此,可以检测,重写,插入或添加这样的 cookie,让客户端记住分配了哪个服务器

  • 服务器可以决定在注销时更改或清除粘性 cookie,以便离开的访问者自动从服务器解除绑定

  • 使用基于 ACL 的规则,无论服务器的状态如何,都可以选择性地忽略或强制粘性,结合高级健康检查,帮助管理员验证他们正在安装的服务器是否正常运行,再对外服务

  • 在 cookie 上设置最大空闲时间(maximum idle time)和持续时间(duration)的机制可确保在永不关闭的设备(智能手机,电视,家用电器)上顺利停止粘性,而无需将其存储在持久存储上

  • 多个服务器条目可以共享相同的粘性键,以便在一个路径发生故障时多路径环境中不会丢失粘性

  • 软停止(soft-stop)确保只有具有粘性信息的用户才能继续访问他们已被分配到的服务器,但新用户不能被分配到那些服务器

采样与转换信息

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 或使用其他样本的某些操作进行快速更新,使它们能够在后续访问到来前完成存储和检索信息。 另一个优势来自基于二叉树的索引,即使它们包含数十万个条目,它们也非常快,使得位置定位非常方便且易于设置。

ACLS 和条件

HAProxy 中的大多数操作都可以是有条件的。 通过使用逻辑运算符(AND,OR,NOT)组合多个 ACL 来构建条件。 每个 ACL 都是基于以下元素的一系列测试:

  • 用于检索要测试的元素的示例获取方法
  • 一系列可选的转换元件
  • 要匹配的模式列表
  • 一种匹配方法,用于指示如何将模式与样本进行比较

例如,可以从 HTTP“主机”头部获取样本,然后可以将其转换为小写,然后使用正则表达式匹配方法与多个正则表达式模式进行匹配。

从技术上讲,ACL 与映射构建在同一个核心上,它们共享完全相同的内部结构,模式匹配方法和性能。 唯一真正的区别是,ACL 只返回“找到”或“未找到”,而不是返回样本。 在使用方面,ACL 模式可以在配置文件中内联声明,并且不需要自己的文件。 可以命名 ACL 以便于使用或使配置易于理解。 命名 ACL 可以多次声明,它将依次评估所有定义,直到匹配为止。

提供了大约 13 种不同的模式匹配方法,其中包括 IP 地址掩码,整数范围,子串,正则表达式。 它们像函数一样工作,就像使用任何编程语言一样,只评估所需的内容,因此当涉及 OR 的条件已经为真时,不会评估下一个条件,并且当涉及 AND 的条件已经为假时,其余的条件则无需评估。

声明的 ACL 的数量没有实际限制,并且提供了少数常用的 ACL。 但是经验表明,使用大量命名 ACL 的设置很难排除故障,并且有时使用内联匿名 ACL 更容易,因为它需要更少的分析范围之外的引用。

内容转换

HAProxy 实现了一种称为基于内容的转换机制。 原则是连接或请求到达前端,然后处理此请求或连接携带的信息,此时可以编写基于 ACL 的条件,利用这些信息来决定哪些后端处理请求。 因此,根据请求的内容将流量引导到一个后端或其他后端。 最常见的示例包括使用路径中的 Host 头和 / 或元素(子目录或文件扩展名)来确定 HTTP 请求是针对静态对象还是应用程序,以及将静态对象流量路由到后端快速轻量的服务器,以及所有剩余流量路由到更复杂的应用服务器,从而构成了一个细粒度的虚拟主机解决方案。 这可以方便地使多种技术作为更全面的解决方案共存。

内容交换的另一个用例包括根据各种标准使用不同的负载均衡算法。 缓存可以使用 URI 哈希,而应用程序将使用循环法(round-robin)。

最后,它允许多个客户通过强制执行每个后端(因此按客户连接限制)来使用一小部分公共资源。

内容转换规则可以很好地扩展,但其性能可能取决于所使用的 ACL 的数量和复杂性。 但是,也可以编写动态内容转换规则,其中样本值直接变为后端名称,而根本不使用 ACL。 据报道,这种配置在生产中至少有 300000 个后端工作正常。

绑定表

绑定表(stick table)通常用于存储粘性信息,即保持对某个访问者所指向的服务器的引用。 然后,密钥是与访问者关联的标识符(其源地址,连接的 SSL ID,HTTP 或 RDP cookie,从 URL 或有效负载中提取的客户编号,…),然后存储的值为服务器的标识符。

绑定表可以使用 3 种不同类型的样本作为其键:整数,字符串和地址。 代理中只能引用一个绑定表,并且在任何地方都使用代理名称指定它。 最多可以并行跟踪 8 个键。 一旦密钥和服务器都已知,就在请求或响应处理期间提交服务器标识符。

绑定表内容可以在主主(active-active)模式下与其他 HAProxy 节点(称为“对等节点(peer)”)以及重新加载操作期间的新进程一起复制,以便如果客户机的请求分布在多个节点上,则所有负载均衡节点共享相同的信息并做出相同的路由决策。

由于绑定表是基于允许识别客户端的索引,因此它们通常还用于存储额外信息,例如每个客户端的统计信息。 额外的统计信息需要一些额外的空间,需要明确声明。 可以存储的统计类型包括输入和输出带宽,并发连接数,一段时间内的连接速率和计数,错误的数量和频率,一些特定的标签和计数器等。为了支持保持这些信息在不被强制绑定到给定服务器,它实现了一个特殊的“跟踪”特性,允许同时跟踪来自不同表的 3 个键,而不考虑粘性规则。 可以从 CLI 搜索,转储和清除每个存储的统计信息,并添加到实时故障排除功能。

虽然这种机制可以用来代表返回的访问者或根据好的或坏的行为来调整提供的服务质量,但它主要用于对抗服务滥用(service abuse),更常见的是 DDoS,因为它允许构建复杂的模型,以高处理速度检测某些不良行为。

格式化字符串

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

HTTP 重写与重定向

如果没有合适的工具,在从未为此设计的应用程序前面安装负载均衡器可能是一项具有挑战性的任务。 在这种情况下,最常请求的操作之一是调整请求和响应头,以使负载均衡器显示为源服务器并修复硬编码信息。 这需要更改请求中的路径(强烈建议不要这样做),修改主机头字段,修改重定向的位置响应头字段,修改 cookie 的路径和域属性等。 还有一些服务器有些冗长,往往会在响应中泄漏太多信息,使它们更容易受到针对性攻击。 虽然理论上讲负载均衡器并不能解决这个问题,但实际上它位于基础设施中最好的位置,以保证一切都被清理干净。

同样,有时负载均衡器必须拦截某些请求,并通过重定向到新的目标 URL 进行响应。 虽然有些人往往混淆重定向和重写,但这些是两个完全不同的概念,因为重写使客户端和服务器看到不同的东西(并且访问页面的位置不一致),而重定向则要求客户端访问新的 URL,以便它看到与服务器相同的位置。

为此,HAProxy 支持各种重写和重定向的可能性,其中包括:

  • 请求和响应中基于正则表达式的 URL 和报头重写。 正则表达式是最常用的修改报头值的工具,因为它们易于操作和易于理解

  • 也可以根据格式化字符串附加,删除或替换报头,以便传递信息(例如客户端 TLS 算法和密码)

  • HTTP 重定向可以使任何 3xx 代码重定向到相对,绝对或完全动态(格式化的字符串)的 URI

  • HTTP 重定向还支持一些额外的选项,例如设置或清除特定 cookie,删除查询字符串,如果缺少则附加斜杠等

  • 所有操作都支持基于 ACL 的条件

服务器保护

HAProxy 可以最大限度地提高服务可用性,为此,需要付出巨大努力来保护服务器免受过载和攻击。 第一个也是最重要的一点是,只有完整有效的请求才会被转发到服务器, 最初的原因是 HAProxy 需要找到它与字节流保持同步所需的协议元素,第二个原因是在请求完成之前,无法知道某些元素是否会改变其语义。 这样做的直接好处是服务器不会暴露于无效或不完整的请求。 这是一种非常有效的防止慢速逃逸攻击(slowloris attacks)的保护措施,对 HAProxy 几乎没有任何影响。

另一个重要的点是,HAProxy 包含用于存储请求和响应的缓冲区,并且仅在服务器完成时向服务器发送请求,并通过从本地网络快速读取整个响应,服务器端的连接只在短时间内被使用,这将尽可能地保留服务器资源。

对此的直接扩展是 HAProxy 可以人为地限制并发连接的数量或服务器未完成的请求,这保证了服务器永远不会过载,即使它在流量高峰期间不断以 100%的容量运行。当一个插槽被释放时,所有多余的请求将被排队等待处理。 最后,这种巨大的资源节省通常可以确保更好的服务器响应时间,最终实际上比通过重载服务器更快。排队的请求可能被重新分配到其他服务器,甚至在客户端中止时在队列中中止,这也保护服务器免受“重新加载效应(reload effect)”的影响,即访问者在缓慢加载的页面上每次点击“重新加载”通常会导致新请求,使服务器维持在过载状态。

慢启动机制还可以在服务器仍在完成启动或编译某些类时保护服务器不受高流量水平的影响。

关于协议级保护,可以放宽 HTTP 解析器以接受非标准兼容但无害的请求或响应,甚至修复它们。这允许在开发修复程序时访问伪造应用程序。 同时,使用详细报告完全捕获有问题的消息,该报告可帮助开发人员发现应用程序中的问题。最危险的协议违规会被正确检测和处理并修复。 例如,如果值完全相同,则具有两个 Content-length 头的格式错误的请求或响应将被修复,或者如果它们不同则被拒绝,因为它会成为安全问题。 协议检查不仅限于 HTTP,它也可用于其他协议,如 TLS 或 RDP。

当检测到协议违规或攻击时,有多种选项可以响应用户,例如返回常见的“HTTP 400 bad request”,使用 TCP 重置关闭连接,或者在长时间延迟后伪造错误(“tarpit”)迷惑攻击者。 所有这些都有助于通过阻止违规客户端进行维护成本非常高的攻击来保护服务器。

HAProxy 还提出了一些更高级的选项来防止意外数据泄漏和会话交叉(session crossing)。 它不仅可以记录可疑的服务器响应,还会记录并可选地阻止可能影响指定访问者机密性的响应。 一个这样的示例,可缓存的响应出现在可缓存的 cookie 中,可以导致中间缓存将其传递给另一个访问者,从而导致意外的会话共享。

日志

对于负载均衡器来说,日志记录是一个非常重要的功能,首先是因为负载均衡器经常被错误地指责导致了它显现的问题,其次是因为它被放置在需要分析所有正常和异常活动的基础设施中的关键点并与其他组件相关联。

HAProxy 提供非常详细的日志,具有毫秒精度,和可在防火墙日志中搜索的确切连接接受时间(例如,用于 NAT 关联)。 默认情况下,TCP 和 HTTP 日志非常详细,包含故障排除所需的所有内容,例如源 IP 地址和端口,前端,后端,服务器,计时器(请求接收持续时间,队列持续时间,连接建立时间,响应报头时间,数据传输时间),全局进程状态,连接计数,队列状态,重试次数,详细的粘性操作和断开连接原因,带有安全输出编码的报头捕获(header captures)。然后可以扩展或替换此格式以包括任何采样数据,变量,捕获,从而产生非常详细的信息。 例如,可以记录客户端访问的累积请求数或不同 URL。

可以使用标准 ACL 根据请求调整日志级别,因此可以自动静默一些脏日志,不会在一小部分流量发生某些异常行为时引发警告(例如,过多的 URL 或一个源地址的 HTTP 错误)。 管理日志也以其自己的级别发出,以通知服务器的丢失或恢复。

每个前端和后端可以使用多个独立的日志输出,这可以简化多租户。 日志优选地通过 UDP 发送,可能是 JSON 编码的,并且在可配置的线长度(line length)之后被截断以便保证传送。

统计

HAProxy 提供基于 Web 的统计报告界面,其中包含身份验证,安全级别和范围。 因此,可以为每个托管客户(hosted customer)提供他自己的页面,仅显示他自己的实例。 此页面可以位于常规网站的隐藏 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:这是日志分析工具,它可以非常快速地解析本机 TCP 和 HTTP 日志(每秒 1 到 2GB)并提取有用的信息和统计信息,例如每个 URL 的请求,每个源地址,已根据响应时间或错误率排序的 URL ,终止代码等。它是为了在生产服务器上部署帮助解决问题,所以必须准备使用
  • tcpdump:强烈建议您使用所需的网络跟踪来解决日志中可见的问题。 有一段时间,应用程序和 haproxy 的分析会发生分歧,网络跟踪是判断谁对谁错的唯一方法。 由于 tcpdump,在网络堆栈和管理程序中检测 bug 也相当常见。
  • strace:这是 tcpdump 的附件。 它将报告 HAProxy 真正看到的内容,并将帮助从 HAProxy 负责的问题中找出操作系统负责的问题。 当怀疑 HAProxy 中存在错误时,通常会要求 Strace

系统特定功能

根据部署的 HAProxy 操作系统,可能会提供或需要某些额外功能。 虽然它在许多平台上都受支持,但 HAProxy 主要是在 Linux 上开发的,这解释了为什么某些功能仅在此平台上可用。

透明绑定和连接功能,对绑定连接到特定网络接口的支持,以及将多个进程绑定到相同 IP 地址和端口的功能仅在 Linux 和 BSD 系统上可用,虽然只有 Linux 对可用进程之间的传入请求执行内核端负载均衡。

在 Linux 上,还有许多额外的功能和优化,包括支持网络命名空间(也称为“容器”),允许 HAProxy 成为所有容器之间的网关,能够在客户端连接上设置 MSS,Netfilter 标记和 IP TOS 字段,在监听端支持 TCP FastOpen,TCP 用户超时(user timeouts)让内核在检测到客户端在配置的超时时间之前消失时快速终止连接,TCP 拼接(splicing)让内核在连接的两端之间转发数据,从而避免多个内存副本,启用“defer-accept”绑定选项的能力只有在内核缓冲区中数据可用时才会收到传入连接的通知,并且能够通过 ACK 确认连接发送请求(有时称为“背驮式(piggy-back)”),通过使用“tcp-smart-connect”选项启用。 在 Linux 上,HAProxy 还非常注意操纵 TCP 延迟的 ACK,以便在网络上保存尽可能多的数据包。

有些系统有一个不可靠的时钟,它在过去和将来会来回跳跃。这种情况曾经发生在一些 NUMA 系统中,其中多个处理器没有观察到完全相同的时间,并且最近它在虚拟化环境中变得更加普遍,其中虚拟时钟与真实时钟无关,导致巨大的时间跳跃(有时已观察到长达 30 秒)。这通常会导致很多关于超时执行的麻烦。 由于这些系统的缺陷,HAProxy 保持其自己的单调时钟,该时钟基于系统的时钟,但是会测量和补偿时钟漂移。这确保即使系统时钟非常糟糕,定时器仍然保持相当准确,并且超时也可以继续工作。 请注意,此问题会影响在此类系统上运行的所有软件,并非特定于 HAProxy。常见的影响是虚假超时(spurious timeouts)或应用冻结(application freezes)。 因此,如果在系统上检测到此行为,则必须修复此行为,而不管 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 上发现了以下数字,配备了运行 Linux 内核 3.10,HAProxy 1.6 和 OpenSSL 1.0.2 的双端口 10 Gbps 网卡。 HAProxy 在单个专用 CPU 内核上作为单个进程运行,另外两个内核专用于网络中断:

  • 对于 256kB 或更高的对象,明文的 20Gbps 最大网络带宽;对于 41kB 或更高的对象,为 10Gbps
  • 使用带有大型对象的 AES256-GCM 密码的 4.6 Gbps TLS 流量
  • 从客户端到服务器每秒 83000 个 TCP 连接
  • 从客户端到服务器每秒 82000 个 HTTP 连接
  • 服务器关闭(server-close)模式下每秒 97000 个 HTTP 请求(与客户端保持活跃状态,与服务器关闭)
  • 端到端保持(end-to-end keep-alive)模式下每秒 243000 个 HTTP 请求
  • 每秒 300000 个过滤的 TCP 连接(反 DDoS)
  • 在持久 TLS 连接上的 keep-alive 模式下每秒 160000 个 HTTPS 请求
  • 使用 TLS 恢复连接,每秒 13100 个 HTTPS 请求
  • 使用与 RSA2048 重新协商的 TLS 连接,每秒 1300 个 HTTPS 连接
  • 每 GB 内存 20000 个并发饱和连接,包括系统缓冲区所需的内存,通过仔细调整可以做得更好,但这很容易实现。
  • 每 GB 内存大约 8000 个并发 TLS 连接(仅客户端),包括系统缓冲区所需的内存
  • 每 GB 内存大约 5000 个并发端到端 TLS 连接(双方),包括系统缓冲区所需的内存

因此,要记住的一个好的经验法则是请求率是 TLS 保持活动和 TLS 恢复之间数除以 10,或 TLS 恢复和 TLS 重新协商之间的数除以 10,或 HTTP keepalive 和 HTTP close 之间的值除以 3。 另一个是,带有 AES 指令的高频核心可以为每个核心提供大约 5 Gbps 的 AES-GCM。

拥有更多内核并不会有用(TLS 除外),并且由于频率较低而甚至会适得其反。 通常,少量但高频的核心更好。

另一个好的经验法则是考虑在同一台服务器上,HAProxy 将能够饱和:

  • 大约 5-10 个静态文件服务器或缓存代理
  • 约 100 个反病毒代理
  • 大约 100-1000 个应用服务器,取决于所使用的技术

配套产品及替代产品

HAProxy 与下面列出的某些产品集成得相当好,这就是为什么在这里提到它们,即使它们与 HAProxy 没有直接关系。

Apache

Apache 是一个实际的标准 HTTP 服务器。 这是一个非常完整的模块化项目,支持文件服务和动态内容。 它可以作为某些应用程序服务器的前端, 甚至可以代理请求和缓存响应。 在所有这些使用案例中,通常需要前负载均衡器。 Apache 可以在各种模式下工作,有些模式比其他模式更繁重。 某些模块仍然需要较繁重的预分叉(pre-forked)模型,并且会阻止 Apache 通过大量连接进行良好的扩展。 在这种情况下,HAProxy 可以通过将每个服务器的连接限制强制设置为一个安全值来提供极大的帮助,并且可以显著提高服务器的速度,并保存应用程序可以更好地使用的资源。

Apache 可以使用“mod_rpaf”扩展名从 X-Forwarded-For 报头中提取客户端的地址。 当在其配置中指定“option forwardfor”时,HAProxy 将自动提供此报头。 当暴露于互联网时,HAProxy 也可以为 Apache 提供良好的保护,它可以更好地抵御各种类型的 DoS 攻击。

Nginx

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

Varnish

Varnish 是一种智能缓存反向代理,可能最好的描述是 Web 应用程序加速器。 Varnish 没有实现 SSL/TLS,并希望将其所有 CPU 周期专用于最佳功能。 Varnish 还实现了 HAProxy 的 PROXY 协议,因此 HAProxy 可以很容易地作为 SSL 卸载程序和负载均衡器部署在 Varnish 前面,并将所有相关的客户端信息传递给它。此外,当服务器提供压缩对象时,Varnish 自然支持从缓存中解压缩,但是不会压缩。 然后,当后端服务器不实现压缩时,可以使用 HAProxy 压缩传出数据,除非流量较小,否则在负载均衡器上压缩并不是一个好主意。

在跨多个节点构建大型缓存集群时,HAProxy 可以使用一致的 URL 哈希来智能地将负载分配给缓存节点,避免缓存重复,从而得到一个总缓存大小,即所有缓存节点的总和。

替代产品

Linux 虚拟服务器(LVS 或 IPVS)是 Linux 内核中包含的第 4 层负载均衡器。 它在数据包级别工作并处理 TCP 和 UDP。 在大多数情况下,它更多的是补充而不是替代,因为它根本没有第 7 层知识。

Pound 是另一个著名的负载均衡器。它比 HAProxy 简单得多,功能也少得多,但对于许多非常基本的设置,都可以使用这两种方法。它的作者总是首先关注代码的可审计性,并希望保持少量的特性。它的基于线程的体系结构在连接计数高的情况下伸缩性较差,但它是一个很好的产品。

Pen 是一款非常轻的负载均衡器。它支持 SSL,使用客户机 IP 地址的固定大小表维护持久性。它支持面向包的模式,允许它在一定程度上支持直接服务器返回和 UDP。它适用于小负载(持久性表只有 2048 个条目)。

NGINX 可以在某种程度上进行一些负载均衡,尽管它显然不是它的主要功能。 生产流量用于检测服务器故障,负载均衡算法更受限制,并且粘性非常有限。 但是在它已经存在的一些简单部署场景中它是有意义的。 好处是,由于它与 HAProxy 的集成非常好,因此在达到其限制后添加 HAProxy 没有任何问题。

Varnish 还对其后台服务器进行了一些负载均衡,并支持真正的健康检查。但是它并没有实现粘性,所以就像 NGINX 一样,只要不需要粘性,这就足够了。同样,由于 HAProxy 和 Varnish 集成得非常好,所以很容易在以后将其混用以补充功能集。