Apache vs Nginx 性能:优化技术

几年前,Apache 基金会的 Web 服务器(简称为“Apache”)无处不在,以至于成为“Web 服务器”一词的同义词。 它在 Linux 系统上的守护进程名为 httpd(简称 http 进程)——并且预装在主要的 Linux 发行版中。

它最初于 1995 年发布,引用维基百科的话,“它在万维网的最初发展中发挥了关键作用”。 根据 W3techs,它仍然是最常用的 Web 服务器软件。 然而,根据那些显示过去十年的一些趋势的报告以及与其他解决方案的比较,其市场份额正在下降。 Netcraft 和 Builtwith 给出的报告略有不同,但都一致认为 Apache 的市场份额呈下降趋势,而 Nginx 正在增长。

Nginx——发音为 engine x——由 Igor Sysoev 于 2004 年发布,其明确的意图是超越 Apache。 Nginx 的网站上有一篇比较这两种技术的文章值得一读。 起初,它主要用作 Apache 的补充,主要用于提供静态文件,但它一直在稳步增长,因为它一直在发展以处理各种 Web 服务器任务。

它通常用作反向代理、负载平衡器和 HTTP 缓存。 CDN 和视频流提供商使用它来构建性能至关重要的内容交付系统。

Apache 已经存在很长时间了,它有很多模块可供选择。 众所周知,管理 Apache 服务器是用户友好的。 动态模块加载允许编译不同的模块并将其添加到 Apache 堆栈中,而无需重新编译主服务器二进制文件。 通常,模块将位于 Linux 发行版存储库中,在通过系统包管理器安装它们之后,可以使用 a2enmod 等命令将它们优雅地添加到堆栈中。 Nginx 还没有看到这种灵活性。 当我们查看为 HTTP/2 设置 Nginx 的指南时,模块是 Nginx 需要构建的东西——在构建时配置。

另一个促成 Apache 市场规则的特性是 .htaccess 文件。 它是 Apache 的灵丹妙药,使其成为共享主机环境的首选解决方案,因为它允许在目录级别控制服务器配置。 Apache 服务的服务器上的每个目录都可以有自己的目录 .htaccess 文件。

Nginx 不仅没有等效的解决方案,而且由于性能下降而不鼓励这种使用。

服务器供应商市场份额 1995–2005。 数据来自 Netcraft

LiteSpeed 或 LSWS 是一个服务器竞争者,它具有可与 Apache 相媲美的灵活性,同时又不牺牲性能。 它支持 Apache 风格 .htaccess, mod_securitymod_rewrite,对于共享设置值得考虑。 它被计划作为 Apache 的直接替代品,并与 cPanel 和 Plesk 一起工作。 自 2015 年以来,它一直支持 HTTP/2。

LiteSpeed 具有三个许可层,OpenLiteSpeed、LSWS Standard 和 LSWS Enterprise。 Standard 和 Enterprise 带有可选的缓存解决方案,可与 Varnish LSCache 相媲美,它内置于服务器本身,可以通过重写规则进行控制,在 .htaccess 文件(每个目录)。 它还带有一些内置的 DDOS 缓解“电池”。这与它的事件驱动架构一起,使其成为一个强有力的竞争者,主要针对以性能为导向的托管服务提供商,但即使是较小的服务器或网站。

硬件注意事项

在优化我们的系统时,我们怎么强调都不够重视我们的硬件设置。 无论我们为我们的设置选择这些解决方案中的哪一个,拥有足够的 RAM 都是至关重要的。 当 Web 服务器进程或 PHP 之类的解释器没有足够的 RAM 时,它们就会开始交换,有效交换意味着使用硬盘来补充 RAM 内存。 这样做的结果是每次访问此内存时都会增加延迟。 这将我们带到第二点——硬盘空间。 使用快速 SSD 存储是我们网站速度的另一个关键因素。 我们还需要注意 CPU 的可用性,以及服务器数据中心与目标受众之间的物理距离。

要深入了解性能调整的硬件方面,Dropbox 有一篇很好的文章。

监控

监控我们当前服务器堆栈性能的一种实用方法,每个进程的详细信息,是 htop,它适用于 Linux、Unix 和 macOS,并为我们提供进程的彩色概览。

其他监控工具包括 New Relic(一种具有全套工具的高级解决方案)和 Netdata(一种开源解决方案,它提供出色的可扩展性、细粒度指标和可自定义的 Web 仪表板,适用于小型 VPS 系统和监控网络)服务器。 它可以通过电子邮件、Slack、pushbullet、Telegram、Twilio 等为任何应用程序或系统进程发送警报。

Monit 是另一个无外设的开源工具,它可以监控系统,并可以配置为提醒我们,或重启某些进程,或在满足某些条件时重启系统。

测试系统

AB — Apache Benchmark — 是 Apache Foundation 的简单负载测试工具,而 Siege 是另一个负载测试程序。 这篇文章解释了如何设置它们,这里我们有一些更高级的 AB 技巧,而对 Siege 的深入了解可以在这里找到。

如果您更喜欢 Web 界面,可以使用 Locust,这是一种基于 Python 的工具,可以非常方便地测试网站性能。

安装 Locust 后,我​​们需要在启动它的目录中创建一个 locustfile:

from locust import HttpLocust, TaskSet, task

class UserBehavior(TaskSet):
    @task(1)
    def index(self):
        self.client.get("https://www.sitepoint.com/")

    @task(2)
    def shop(self):
        self.client.get("/?page_id=5")

    @task(3)
    def page(self):
        self.client.get("/?page_id=2")

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 300
    max_wait = 3000

然后我们只需从命令行启动它:

locust --host=https://my-website.com

这些负载测试工具的一个警告:它们具有 DDoS 攻击的效果,因此建议您将测试限制在您自己的网站上。

调整阿帕奇

Apache 的 mpm 模块

Apache 可以追溯到 1995 年和互联网的早期,当时服务器运行的公认方式是在每个传入的 TCP 连接上生成一个新进程并对其进行回复。 如果有更多的连接进来,就会创建更多的工作进程来处理它们。 产生新进程的成本很高,Apache 开发人员设计了一种预分叉模式,具有预先产生的进程数。 每个进程中的嵌入式动态语言解释器(如 mod_php)仍然很昂贵,并且 Apache 默认设置的服务器崩溃变得很常见。 每个进程只能处理一个传入连接。

该模型在 Apache 的 MPM(多处理模块)系统中称为 mpm_prefork_module。 根据 Apache 的网站,这种模式需要很少的配置,因为它是自我调节的,最重要的是 MaxRequestWorkers 指令要大到足以处理您期望接收的尽可能多的同时请求,但又要小到足以确保有足够的物理 RAM 供所有进程使用。

一个小型的 Locust 负载测试,显示生成大量 Apache 进程来处理传入流量。

我们可以补充说,这种模式可能是 Apache 名声不好的最大原因。 它可能会导致资源效率低下。

Apache 的版本 2 带来了另外两个 MPM,它们试图解决 prefork 模式存在的问题。 这些是工作模块或 mpm_worker_module 和事件模块。

Worker 模块不再基于进程; 它是一种基于混合进程线程的操作模式。 引用 Apache 的网站,

单个控制进程(父进程)负责启动子进程。 每个子进程创建固定数量的服务器线程,如 ThreadsPerChild 指令,以及侦听连接并在连接到达时将它们传递给服务器线程进行处理的侦听器线程。

这种模式的资源效率更高。

Apache 2.4版本为我们带来了第三个MPM——事件模块。 它基于 worker MPM,并添加了一个单独的监听线程,用于在 HTTP 请求完成后管理休眠的保活连接。 它是一种非阻塞、异步模式,具有更小的内存占用。 有关 2.4 版改进的更多信息,请参见此处。

我们已经在虚拟服务器上加载了一个包含大约 1200 个帖子的测试 WooCommerce 安装,并在 Apache 2.4 上使用默认、prefork 模式和 mod_php 对其进行了测试。

首先,我们在 https://tools.pingdom.com 上使用 libapache2-mod-php7 和 mpm_prefork_module 对其进行了测试:

然后,我们去测试事件 MPM 模块。

我们不得不添加 multiverse 给我们的 /etc/apt/sources.list:

deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu xenial-security main restricted universe multiverse
deb http://archive.canonical.com/ubuntu xenial partner

然后我们做了 sudo apt-get update并安装 libapache2-mod-fastcgi 和 php-fpm:

sudo apt-get install libapache2-mod-fastcgi php7.0-fpm

由于 php-fpm 是独立于 Apache 的服务,因此需要重新启动:

sudo service start php7.0-fpm

然后我们禁用了 prefork 模块,并启用了事件模式和 proxy_fcgi:

sudo a2dismod php7.0 mpm_prefork
sudo a2enmod mpm_event proxy_fcgi

我们将这段代码添加到我们的 Apache 虚拟主机中:

<filesmatch ".php$">
    SetHandler "proxy:fcgi://127.0.0.1:9000/"
</filesmatch>

这个端口需要和php-fpm中的配置保持一致 /etc/php/7.0/fpm/pool.d/www.conf. 有关 php-fpm 设置的更多信息,请参见此处。

然后我们调整了 mpm_event 配置 /etc/apache2/mods-available/mpm_event.conf, 请记住,我们用于此测试的迷你 VPS 资源是有限的——因此我们只是减少了一些默认数量。 有关 Apache 网站上每个指令的详细信息,以及此处针对事件 mpm 的提示。 请记住,无论服务器有多忙,启动的服务器都会消耗一定量的内存。 这 MaxRequestWorkers 指令设置允许同时请求的数量限制:设置 MaxConnectionsPerChild 为非零值很重要,因为它可以防止可能的内存泄漏。

<ifmodule mpm_event_module>
        StartServers              1
        MinSpareThreads          30
        MaxSpareThreads          75
        ThreadLimit              64
        ThreadsPerChild          30
        MaxRequestWorkers        80
        MaxConnectionsPerChild   80
</ifmodule>

然后我们重新启动服务器 sudo service apache2 restart (如果我们更改一些指令,比如 ThreadLimit,我们将需要显式地停止和启动服务,使用 sudo service apache2 stop; sudo service apache2 start).

我们在 Pingdom 上的测试现在显示页面加载时间减少了一半以上:

调整 Apache 的其他技巧:

禁用 .htaccess:htaccess 允许为服务器根目录中的每个目录设置特定配置,而无需重新启动。 因此,在每次请求时遍历所有目录、查找 .htaccess 文件都会导致性能下降。

引自 Apache 文档:

一般来说,你应该只使用 .htaccess 当您无权访问主服务器配置文件时的文件。* …通常,使用 .htaccess 文件应尽可能避免。 您考虑放入的任何配置 .htaccess 文件,可以同样有效地在 <directory> 主服务器配置文件中的部分。*

解决方案是禁用它 /etc/apache2/apache2.conf:

AllowOverride None

如果特定目录需要它,我们可以在虚拟主机文件的部分中启用它:

AllowOverride All

进一步的提示包括:

    使用 mod_expires 控制浏览器缓存——通过设置过期标头。

    保持 HostNameLookups 关闭 — HostNameLookups Off 是自 Apache 1.3 以来的默认设置,但请确保它保持关闭状态,因为它会导致性能下降。

    Apache2buddy 是一个简单的脚本,我们可以运行它并获得调整系统的提示: curl -sL https://raw.githubusercontent.com/richardforth/apache2buddy/master/apache2buddy.pl | perl

Nginx

Nginx 是一个事件驱动的非阻塞网络服务器。 引用 Hacker News 上的一张海报,

与事件循环相比,分叉进程非常昂贵。 基于事件的 HTTP 服务器不可避免地获胜。

这一声明在 Hacker News 上引发了相当大的争论,但根据我们的经验,仅仅从 mpm_prefork Apache 切换到 Nginx 通常意味着可以避免网站崩溃。 简单地切换到 Nginx 通常本身就是一种治疗方法。

可以在此处找到对 Nginx 体系结构的更全面的可视化解释。

Nginx 设置

Nginx…

阅读更多

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注