HAProxy Technologies 正式宣布推出 HAProxy 1.9。新版本带来了基于原生 HTTP 表示(HTX)的端到端 HTTP/2 支持,并为未来的创新——如 HTTP/3(QUIC)——铺平了道路。它还带来了缓冲区和连接管理方面的改进,包括到后端的连接池、线程优化、Runtime API,等等。
HAProxy 是世界上速度最快、使用最为广泛的软件负载均衡器,于 2001 年 12 月首次发布。从那时起,负载均衡器格局发生了重大变化。17 年来,HAProxy 一直在演化和创新,现在终于迎来了 HAProxy 1.9。
新版本的重点是为我们以后能够继续提供一流的性能和交付尖端功能奠定基础。得益于 1.9 版本的核心改进,一些令人兴奋的功能包括 Layer 7 重试机制、回路断路、gRPC、新的数据平面 API,等等。
我们还发现需要更频繁地发布更新。在未来,HAProxy 将从一年发布一次改为一年两次。之前,主要版本会在每年的 11 月或 12 月份左右发布,但从现在开始,我们将每年发布两次。请注意,这次的版本向后兼容旧的配置。
接下来,我们将深入探讨新版本带来的改进。
缓冲区改进
HAProxy 已经支持到客户端的 HTTP/2。新版本的主要目标是支持端到端的 HTTP/2,包括到后端服务器的 HTTP/2。我们还希望能够支持未来版本的 HTTP,例如 HTTP/3(QUIC)。
我们的研发团队付出了巨大的努力来实现这一目标,其中一个非常重要的方面涉及 HAProxy 处理缓冲区的方式。
缓冲区是一个存储区域,分为两部分:输入数据和输出数据。缓冲区可以在任何地方开始和结束。在之前版本的 HAProxy 中,有 22 种可能的缓冲区,如下图所示:
上图显示了 1.9 版本之前的各种缓冲区及其分配方式。我们决定重写缓冲区处理逻辑并简化缓冲区分配。下图显示了最新的缓冲区变更:
最新的变更将缓冲区的数量减少到 7 个,只需维护一个版本的代码。
除了这些重构之外,缓冲区的标头(即描述缓冲区状态的附加字段)已从存储区域中分离出来。这意味着对于相同的数据不再强制要求使用单一的表示,多个参与者可以在不同的状态下使用相同的存储。这通常被用在底层的多路复用中,通过读取器和写入器对相同数据块附加别名来避免内存复制(也即“零复制”),从而提升了 HTTP/2 的性能。
实现这一点并非易事,但却带来了很多好处。它为更容易实现端到端 HTTP/2 铺平了道路。它还简化了其他一些东西,比如内部 API、错误消息处理和渲染统计页面。
连接管理
HAProxy 1.9 中的连接管理获得了一些重大改进。新的实现已从面向回调的模型转变为异步事件模型(包含了完成回调)。这种新设计将会非常有用,并减少连接层中可能出现的 bug 数量。
新设计的一些好处包括:较低的 send()延迟(几乎从不进行轮询)、更少的层间往返(更好的 I-cache 效率)、在上层内直接使用、消除代码重复,以及提供较低层的细粒度错误报告。它还为不同协议提供了重试失败连接的能力(例如,如果 ALPN 表明同时支持 HTTP/2 和 HTTP/1,那么在其中一个发生故障时,会自动切换到另一个)。
如果没有设置,http-reuse 指令的默认值为 safe。这意味着到后端服务器的会话的第一个请求始终通过自己的连接发送,后续请求可以重用其他现有的空闲连接。这是几年来一直推荐的方式,现在是时候将其变为默认设置。
此外,HAProxy 现在也提供了连接池。当前端连接消失后,HAProxy 和服务器之间的空闲连接并不会立即被关闭,它们在服务器端保持打开状态,以供其他请求使用。
原生 HTTP 表示(HTX)
在研究支持未来版本 HTTP 所需的路由时,我们决定对 HTTP 消息的内部处理机制进行重新设计。之前,HTTP 消息作为字节流进行传输,数据的分析和处理任务被混合在同一个阶段中进行。
HTTP 信息作为字节流被收集起来,并通过偏移量来操作它们。主结构包含了两个通道:请求/响应和 HTTP 事务。第一个通道对请求和响应消息进行缓冲,将它们视为字符串。HTTP 事务通道有两种状态:一个是响应/请求,另一个包含了标头的偏移量。
因为所有东西都是以偏移量的方式进行保存,所以添加、删除和重写 HTTP 数据就会变得很麻烦,需要不断移动到标头的末尾,在处理响应消息时甚至需要移动到 HTTP 正文的末尾。随着时间的推移,cookie、keep-alive、压缩和缓存都需要操作标头,这项任务因此变得十分昂贵。
新的设计(我们称之为 HTX)为 HTTP 协议创建了内部的原生表示。它提供了一系列强类型、精心设计的标头字段,支持间隙和无序。现在修改标头很简单,只需要将旧标头删除,并在末尾添加新标头即可。
这让针对 HTTP 协议的操作变得更加简单,我们可以维护端到端的 HTTP 传输和语义,并在将 HTTP/2 转换为 HTTP/1.1 或将 HTTP/1.1 转换为 HTTP/2 时获得更高的性能。它将处理和分析相分离,现在分析和格式化发生在连接层,而处理发生在应用层。
由于我们还在进行测试,所以默认情况下尚未启用 HTX。你可以在 defaults、frontend、backend、listen 部分添加下面的选项来启用它:
在启用后,你就可以在后端服务器上使用 HTTP/2。将 alpn h2 添加到服务器配置行中(或者如果你希望让 HAProxy 与服务器协商协议,可以添加 alpn h2,http/1.1)。
这是一个端到端 HTTP/2 的完整示例(frontend+backend):
HAProxy 1.9 还支持 proto h2 指令,这个指令让 HAProxy 可以使用没有 TLS 的 HTTP/2 与支持 HTTP/2 的后端(如 Varnish 和 H2O)通信。你可以使用以下服务器配置启用这项功能:
多线程改进
1.9 版本对线程进行了重大改进。这些改进使得 HAProxy 能够提供卓越的性能。为实现这一目标,我们对任务调度程序进行了重新设计。它现在的工作被分为三个级别:
在所有线程之间共享的优先级感知级别;
无锁、优先级感知级别;
可用于 I/O 的已启动任务。
现在大多数调度可以在没有锁的情况下进行,可以更好地扩展。此外,我们对调度程序的等待队列进行了优化。它们现在大部分都是无锁的。内存分配器是无锁的,并使用了热对象线程缓存,从而带来更快的结构初始化。文件描述符事件缓存基本上也是无锁的,允许更快的并发 I/O 操作。最后,文件描述符的锁已更新,因此使用的频率较低。总的来说,HAProxy 1.9 的线程性能提升了差不多 60%。
缓存改进
我们在 HAProxy 1.8 中引入了小对象缓存(Small Object Cache)。当时,很多人希望获得这些功能,而我们也知道这只一个开始:代理层中的缓存。在内部,我们将其称为 favicon 缓存,因为它仅限用于缓存小于 tune.bufsize 的对象,默认为 16KB。此外,在第一个版本中,它只能缓存返回 HTTP 200 OK 响应码的对象。
而在 HAProxy 1.9 中,你可以缓存最大为 2GB 的对象,使用 max-object-size 进行设置。total-max-size 用于指定缓存的总大小,最大为 4095MB。HAProxy 现在可以缓存返回以下状态码的响应:204、404、405、414 和 501。
HTTP 103
HAProxy 现在支持 HTTP 103 状态码,也称为 Early Hints(RFC8297),它允许你在服务器做出响应之前发送一系列对象链接到客户端。这项特性仍处在早期采用阶段,不过 Early Hints 看起来可能会取代 HTTP/2 服务器推送。
因为以下的一些因素,Early Hints 会比服务器推送更好:
服务器推送可以加速资源的传递,但仅限于服务器允许的资源。换句话说,它必须遵循同源策略,某些情况下会对 CDN 的使用造成影响。而 Early Hints 可以直接指向 CDN 托管的对象。
Early Hints 让浏览器可以使用对象的本地缓存。而服务器推送会要求将请求传输至源,无论客户端是否缓存了响应。
要启用 Early Hints,请在 HAProxy 配置文件中添加类似以下这样的内容:
Runtime API 改进
Runtime API 也得到了更新。首先是修改了 master/worker 模型,简化 worker 的交互,并获得更好的进程可观察性。master 现在有自己的套接字,可以直接用这个套接字与它进行通信。而且套接字可以管理与每个 worker 之间的通信,甚至是那些正在退出的 worker。
要使用这个新功能,需要使用-W 和-S 选项启动 HAProxy。
然后通过 master 套接字连接到 Runtime API,如下所示:
新的 show proc 命令显示了每个进程的正常运行时间。
新的 reload 命令重新加载 HAProxy,并加载了新的配置文件。它与向 master 进程发送 SIGUSR2 信号是完全一样的效果,只是可以在上传新配置文件后由外部程序触发。
命令可以通过 master 套接字发给 worker,在命令前面加上 @符号,加上 worker 的编号。以下是向第一个 worker 发出 show info 命令的示例:
我们还添加了有效载荷支持,可以使用 Runtime API 插入多行文本。在更新 map 文件时这会非常有用。目前还不支持通过 Runtime API 更新 TLS 证书,但 HAProxy 2.0 有可能会支持!
要使用有效载荷更新 map 文件,你需要先 map 的 ID,然后使用 add map 命令添加新行,行间用\n 分隔:
你也可以附加文件内容,比如:
Runtime API 中还新增了一个新的 show activity 命令。它可用于显示每个线程被系统抢占的总 CPU 时间,以及所有任务所经历的平均处理延迟。
同样,如果在 global 中配置启用或通过 Runtime API 启用了 profiling,那么就可以在日志中看到 CPU 时间和延迟。要在 global 中启用 profiling,你需要添加:
通过 Runtime API 启用:
验证是否已启用:
服务器队列优先级控制
HAProxy 1.9 允许你对队列中的连接进行优先级排序。例如,你可以让 JavaScript 或 CSS 文件优先于图像传给客户端。或者,你可以用它改善高级客户的加载时间。另外,可以用它给机器人安排较低的优先级。
通过添加 http-request set-priority-class 指令为 JS 或 CSS 文件设置更高的服务器队列优先级。为了避免由连续高优先级请求导致的饥饿等待,可以通过 set-priority-offset 指令为某些请求设置等待时间上限。将这项功能与 ACL 规则结合使用,你就可以灵活地决定何时以及如何安排连接的优先级。
数字越小,优先级越高。因此,在这里,JavaScript 和 CSS 文件被赋予最高优先级,其次是图像,然后是其他资源。
随机负载均衡算法
我们添加了一个新的随机负载均衡算法。这个算法会选择一个随机数作为一致哈希函数的键。在这个模式下,会用到服务器权重。动态权重更改会立即生效,新添加的服务器也会立即生效。随机负载均衡算法对于大型服务器机群或经常需要添加和删除服务器的场景来说非常有用。使用多个负载均衡器可以降低所有流量被重定向到同一服务器的风险。
hash-balance-factor 指令通过保持分配给服务器的负载接近于平均值来进一步提高负载均衡的公平性,当服务器的响应时间高度可变时,这会非常有用。
要启用随机负载均衡算法,请在 backend 中将 balance 设置为 random。
云原生日志
HAProxy 已经具备了将日志写到 syslog 服务器的能力。但是,在使用 Docker 的微服务架构中,将 syslog 安装到容器中是一种反模式。用户要求使用其他方法来发送日志。我们已经从用户那里收到了相当多这类请求,所以花了一些时间选择了一种最佳的实现方式——非阻塞——我们很高兴已经找到了解决方案!
HAProxy 1.9 提供了三种发送日志的新方法:将它们发送到文件描述符、stdout 或 stderr。可以使用标准的 log 语句添加这些新方法。
要将日志记录到 stdout,请使用 stdout 参数:
对于 stderr 也类似。另一种方法是将日志发送到文件描述符,如下所示:
fd@1 参数是 stdout 的别名,fd@2 是 stderr 的别名。它们还有两种新的日志格式:raw 和 short。
新的 Fetch
HAProxy 中的 Fetch 提供了来自内部状态或 L4、L5、L6 和 L7 的信息。新版本新增了 date_us、cpu_calls、lat_ns_avg 等 Fetch。
新的转换器
转换器可用于在 HAProxy 中转换数据,通常用在 Fetch 之后。新版本新增了 strcmp、concat、length、crc32c 等转换器。
杂项改进
新版本的 HAProxy 还添加了其他各种改进,包括:
新的 stick-table 计数器 gpc1 和 gpc_rate。
resolvers 部分现在支持 resolv.conf。
busy-polling——在启用了频率缩放或支持深度空闲状态的机器上可将请求处理延迟减少 30-100 微秒。
HAProxy 的 Lua 引擎进行了以下更新:
Server 类可更改服务器的 maxconn 值。
TXN 类可调整服务器连接队列优先级。
新类 StickTable 允许通过键来访问和转储 stick-table 的内容。
回归测试套件
Varnish 附带了一个叫作 varnishtest(https://varnish-cache.org/docs/trunk/reference/varnishtest.html)的工具,用于对整个 Varnish 代码库进行回归测试。我们发现它也是用来测试 HAProxy 特定用例的完美工具。我们与 Varnish 团队合作,为 varnishtest 提供补丁,对其进行扩展,并用它来测试 HAProxy。
我们还开始创建和发布可在用户环境中运行的测试代码。如果你了解 HAProxy,编写测试代码就很容易。所以,如果你有兴趣为 HAProxy 做贡献但不知道从哪里开始,你可以尝试先拉取 HAProxy 的代码,然后自己编写测试!
要使用回归测试套件,需要安装 varnishtest,它已经包含在 Varnish 软件包中。安装完成后,你需要创建一个测试 vtc 文件。这是一个示例:
要运行它,需要将 HAPROXY_PROGRAM 环境变量设置为你要测试的二进制文件的路径。然后调用 varnishtest。
HAProxy 2.0 预览
以下是将在 HAProxy 2.0 中带来的功能,计划于 2019 年 5 月发布:
HAProxy 数据平面 API;
gRPC;
L7 重试;
FastCGI 集成;
回路断路;
将 TLS 证书与私钥分离;
使用 Runtime API 更新 TLS 证书和私钥。
结论
在开源社区和 HAProxy Technologies 的大力支持下,HAProxy 始终处于性能和创新的最前沿。我们很高兴为你带来 1.9 版本!它开启了一个新的篇章,你将看到更频繁的版本更新频率。它将支持端到端 HTTP/2,改进了缓冲区和连接管理,更新了 Runtime API 和小对象缓存,提供了新的随机负载均衡算法,甚至通过 Runtime API 和新的 Fetch 获得更好的可观察性。
英文原文:https://www.haproxy.com/blog/haproxy-1-9-has-arrived/
评论 1 条评论