本内容是对知名性能评测博主 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 相比如何。
在这个播放列表中我还有其他你可能会感兴趣的基准测试。感谢观看,我们下个视频再见!
评论记录:
回复评论: