本内容是对知名性能评测博主 Anton Putra Nginx vs Apache Performance 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准
引言
在本视频中,我们将比较 Nginx 与 Apache 这两个 Web 服务器。我们将进行多项测试,并且实际上,在某些情况下,Apache Web 服务器的性能可以超越 Nginx。
我们将使用客户端测量的 P99 百分位延迟来衡量每个请求的延迟时间,我认为这是与吞吐量并列的最重要的指标之一。另一方面,吞吐量将以每秒请求数(requests per second)来衡量,我们将产生足够的负载,以找到这两个 Web 服务器的性能极限点(breaking point)。我们还将衡量可用性或错误率,其定义为成功请求数与总请求数之比。此外,我们将通过跟踪相对于虚拟机限制的 CPU 使用率以及内存使用率来衡量饱和度,即服务的繁忙程度。最后,我们将监控网络流量,因为这两个代理(proxies)压缩内容的速率略有不同。
在第三个动态测试中,我们将衡量这些 Web 服务器作为反向代理和管理负载均衡的效率。此外,在此测试中,我们将衡量代理后面应用程序的饱和度。
为了运行这些测试,我使用了 AWS。我部署了大型独立 EC2 实例来运行 Nginx 和 Apache,并创建了一个包含 4xlarge Graviton 实例的 EKS 集群,用于运行生成负载的我的客户端。此外,对于第三个测试,我使用大型 EC2 实例来托管这些代理后面的应用程序。
测试设计
对于第一个测试,我创建了一个 AWS VPC,并在专用的虚拟机上部署了 Nginx 和 Apache Web 服务器。我使用了 m7a.large EC2 实例,这些实例拥有 2 个虚拟 CPU 和 8 GiB 内存。在此测试中,我使用了一个由 React 生成的静态网站,该网站编译成 HTML、CSS 和 JavaScript 文件,由每个 Web 服务器提供服务。我使用了普通的 HTTP 协议,并在两个 Web 服务器上都启用了压缩功能,因为 HTTP 仍然有一些使用场景,并且这有助于展示 TLS 加密如何影响 Web 服务器的性能和吞吐量。
为了生成负载,我创建了一个包含 Graviton 实例的 EKS 集群,并为每个 Web 服务器部署了大约 20 个 Pod 来模拟流量。
第二个测试非常相似,只是每个 Web 服务器都使用 TLS 证书进行了安全保护。

我设置了一个私有证书颁发机构(CA),为两个 Web 服务器颁发了证书,并将该证书颁发机构提供给每个客户端,以便进行身份验证并建立安全的 HTTPS 连接。此外,我们将协议从 HTTP 升级到 HTTP/2,同时保持相同的压缩设置。这种情况反映了更常见的使用场景,因为互联网上几乎所有的网站都使用 TLS 证书进行保护,尤其是自从 Let's Encrypt 免费提供证书以来。而且,如果网站使用 HTTPS,Google 会给予更高的排名。
对于第三个测试,我不再提供静态内容,而是将每个 Web 服务器用作反向代理,将请求路由到其后面的应用程序。这样做有几个原因:首先,你可以在代理上终止 TLS,并在你的应用程序内部直接处理普通的 HTTP 请求。这也提高了安全性,因为客户端不会直接看到你的服务器 IP。并且,反向代理允许你在应用程序之间扩展和负载均衡流量,还允许你在不中断服务的情况下升级应用程序。

实现概述
我使用的是目前可用的最新版本。Nginx 的版本是 1.26.2,你可以从官方 Ubuntu 仓库轻松安装。然而,Apache 的版本是 2.4.62,目前还不能从官方仓库获取。因此,我不得不从源代码安装它,同时还需要安装 Apache 运行时库、工具库以及其他几个需要编译的依赖项。
如果你想尝试一下,可以在 README 文件中找到一个分步指南,介绍如何从源代码安装最新版本的 Apache。
要验证压缩功能,你可以使用 curl。当你向 Nginx 或 Apache 发送请求时,可以检查响应大小,这个大小也会出现在两个服务器的访问日志中。通过添加一个表示 curl 可以接受 gzip 的标头,你告诉服务器在将每个有效负载发送给客户端之前对其进行压缩。你将在访问日志中看到两个服务器都在发送数据前对其进行了压缩。

要测试 HTTP/2,你也可以使用 curl,并检查访问日志以确认使用了哪个版本的 HTTP 协议。
同样,在这些测试中,我在每个客户端中挂载了一个证书颁发机构,以验证我用于 Web 服务器的自签名证书。
所有的配置,包括 Nginx 服务器块(server blocks)和 Apache 虚拟主机(virtual hosts),都可以在我的公开 GitHub 仓库中找到。如果你发现任何可以改进的地方,请告诉我。
第一个测试
好了,让我们开始运行第一个测试。这里没有什么令人惊讶的------Apache 的延迟是 Nginx 的两到三倍,这清楚地显示了每个 Web 服务器的性能表现。你还会注意到,Apache 处理相同数量的请求使用了明显更多的 CPU,这表明到最后它的吞吐量很可能远低于 Nginx。而且 Apache 使用的内存也稍微多一些。另一方面,Nginx 传输的数据略多,因为它的压缩过程产生的响应更大。

在大约每秒 6,000 个请求时,Apache 的延迟开始增加。这很可能是由于高 CPU 使用率达到了其限制,并且在这个阶段 Apache 的可用性也开始下降。
在大约每秒 8,000 个请求时,Apache 再也跟不上 Nginx 了。此时,Apache 的 CPU 利用率已达到 100%。它可能仍然能处理更多请求,但延迟会很高。现在,让我们继续找出 Nginx 的性能极限点。
当使用普通 HTTP 协议和压缩提供静态网站时,Nginx 每秒可以处理的请求数是 Apache 的三倍以上。这种配置如今不太常见,但如果你有类似的使用场景,这个基准测试会告诉你应该选择哪个 Web 服务器。
现在,让我打开整个测试期间的每个图表。首先是每秒请求数图。Apache 在大约 8,000 RPS 时开始性能下降,而 Nginx 一直坚持到大约 32,000 RPS。

接下来,我们看延迟图。即使在开始时,两者之间的延迟差异也很显著。


然后是可用性图。

接着是 CPU 使用率。

以及内存使用率。

最后,我们有网络使用情况。在峰值时,Nginx 每秒可以向客户端传输近 1 GB 的数据。
基于这个基准测试,如果你通过普通 HTTP 提供静态内容且不进行加密,Nginx 是明确的选择。
第二个测试
第二个测试在今天更为典型,因为大多数网站都需要使用 TLS 证书进行保护。例如,如果发生中间人攻击,TLS 加密可以确保所有数据(如用户名、密码甚至信用卡信息)在 Web 服务器和客户端之间保持安全。然而,使用 TLS 会增加每个 Web 服务器的 CPU 负载,因为每个请求都必须进行加密和解密。但由于我们使用了 TLS,我们可以将 HTTP/1 协议升级到更高效的 HTTP/2 二进制协议。这意味着延迟和吞吐量不一定会像你预期的那样下降。

从延迟图中,你可以看到 Nginx 的表现仍然非常好,延迟几乎与上一个测试相同。Apache 的延迟也与上一个测试相似,但并不是以好的方式相似。
在大约每秒 7,000 个请求时,Apache 开始性能下降,这仅仅比上一个基准测试少了 1,000 个请求。让我们继续找出 Nginx 的性能极限点。

我运行了这个测试几次,因为当 Nginx 达到 85% 的 CPU 使用率时,它会突然跳升到 100%,并且无法处理更多请求。我最初以为可能是基础设施问题,但第二次运行测试时,它再次在大约 85% CPU 使用率时失败。在这个测试中,Nginx 每秒只能处理 22,000 个请求,比上一个测试少了 10,000 个。感觉上 Nginx 在 85% CPU 使用率时似乎能达到每秒 30,000 个请求,但它总是在这个点失败。

好了,让我打开每秒请求数图。

接下来是延迟图。


可用性图。

CPU 使用率。

内存使用率。

最后是网络流量。

基于这个基准测试,Nginx 显然更适合通过 HTTPS 提供静态内容。
第三个测试
最后,让我们运行第三个动态测试。在这里,我们不是提供静态网站,而是将每个 Web 服务器用作代理和负载均衡器。在每个代理后面,我们有两个应用程序副本,每个代理使用轮询(round-robin)方式将流量分配到这些应用程序。
令人惊讶的是,Apache 在这个测试中表现非常好。它的延迟甚至比 Nginx 更低,尽管它确实消耗了稍微多一点的 CPU。真正让我惊讶的是,Nginx 后面应用程序的 CPU 使用率远高于 Apache 后面的应用程序。如果有人能解释这一点,请告诉我。

在这个测试中,我们同样使用了压缩和 TLS 证书,这让我们能够升级到 HTTP/2 协议。在这里,Apache 在压缩方面继续表现更好,产生了更小的响应,正如你在访问日志中看到的那样。
在大约每秒 7,000 个请求时,Apache 开始性能下降,其延迟上升到与 Nginx 相当。从这一点开始,它们的延迟非常相似。

在大约每秒 15,000 个请求时,Nginx 表现出与上一个测试相同的行为。它达到 80% 的 CPU 使用率并立即失败。在这个测试中,Apache 的性能超过了 Nginx。由于 Nginx 在第一个测试中没有表现出这种行为(并且我多次重新运行了该测试),我怀疑 Nginx 处理 TLS 握手或执行加密的方式可能有问题,或者这可能与 HTTP/2 协议有关。压缩在所有三个测试中都启用了。
在大约每秒 21,000 个请求时,Nginx 恢复在线几分钟,然后再次失败。当我重新运行测试时,这种行为发生了多次。

在大约每秒 24,000 个请求时,Apache 达到了其最大吞吐量,无法再处理更多请求。
好了,让我打开每个图表。

首先是每秒请求数图,


然后是延迟图,

可用性图,

以及应用程序 CPU 使用率(这些是反向代理后面的应用程序)。

接下来是两个 Web 服务器的 CPU 使用率。

内存使用率。

网络流量。
最后是代理后面应用程序的内存使用率。

基于这个测试,我并不是建议你切换到 Apache。然而,这些结果让我想要更深入地研究,因为我在几乎管理的每个 Kubernetes 集群中都广泛使用 Nginx 作为入口控制器(ingress controller)。我有兴趣测试其他入口选项,特别是 Apache 入口控制器,看看它与 Nginx 相比如何。
在这个播放列表中我还有其他你可能会感兴趣的基准测试。感谢观看,我们下个视频再见!