简介
Apache 和 Nginx 是世界上两个最常见的开源 Web 服务器。它们共同负责着互联网上超过 50% 的流量。这两个解决方案都能够处理各种工作负载,并与其他软件配合提供完整的 Web 技术栈。
虽然 Apache 和 Nginx 具有许多相似之处,但它们不应被视为完全可互换的。每个都有其自身的优势和劣势,本文将介绍它们各自的长处和短处。
总体概述
在深入探讨 Apache 和 Nginx 之间的区别之前,让我们快速了解一下这两个项目的背景和它们的一般特点。
Apache
Apache HTTP 服务器由 Robert McCool 在 1995 年创建,并自 1999 年以来在 Apache 软件基金会的指导下进行开发。由于 HTTP Web 服务器是该基金会的最初项目,也是迄今为止最受欢迎的软件,因此通常简称为 “Apache”。
Apache Web 服务器至少从 1996 年至 2016 年一直是互联网上最流行的服务器。由于其流行,Apache 受益于出色的文档和来自其他软件项目的集成支持。
管理员通常选择 Apache 是因为其灵活性、强大性和几乎普遍的支持。它通过动态可加载模块系统可扩展,并且可以直接提供许多脚本语言(如 PHP)的服务,而无需额外的软件。
Nginx
2002 年,Igor Sysoev 开始着手开发 Nginx,以解决 C10K 问题,即 Web 服务器能够处理一万个并发连接的问题。Nginx 在 2004 年公开发布,并通过采用异步、事件驱动的架构实现了这一目标。
由于其轻量级的占用空间和在最小硬件上轻松扩展的能力,Nginx 已经超越了 Apache,成为更受欢迎的选择。Nginx 擅长快速提供静态内容,具有自己强大的模块系统,并且可以根据需要将动态请求代理到其他软件。
管理员通常选择 Nginx 是因为其资源效率和在负载下的响应能力,以及其简单直观的配置语法。
连接处理架构
Apache 和 Nginx 之间的一个区别在于它们处理连接和网络流量的具体方式。这可能是它们在负载下响应的最重要的区别。
Apache
Apache 提供了各种多处理模块(Apache 称之为 MPMs),这些模块规定了客户端请求的处理方式。这使管理员可以配置其连接处理架构。这些模块包括:
- mpm_prefork:此处理模块生成具有单个线程的进程来处理请求。每个子进程一次只能处理一个连接。只要请求数量少于进程数量,这种 MPM 就非常快。但是,一旦请求数量超过进程数量,性能就会迅速下降,因此在许多情况下这不是一个很好的选择。每个进程对 RAM 消耗有显著影响,因此这种 MPM 难以有效扩展。但是,如果与其他不考虑线程的组件一起使用,这可能仍然是一个不错的选择。例如,PHP 并不总是线程安全的,因此已经建议使用这种 MPM 作为处理这些文件的 Apache 模块
mod_php
的安全方式。 - mpm_worker:此模块生成可以管理多个线程的进程。每个线程可以处理一个连接。线程比进程更有效,这意味着这种 MPM 比 prefork MPM 更好地扩展。由于线程比进程多,这也意味着新连接可以立即获取一个空闲线程,而不必等待空闲进程。
- mpm_event:此模块在大多数情况下类似于 worker 模块,但经过优化以处理长连接。使用 worker MPM 时,连接将保持一个线程,无论是否正在进行请求,只要连接保持活动状态。event MPM 通过为处理长连接设置专用线程并将活动请求传递给其他线程来处理长连接,从而避免了被长连接请求拖慢,从而实现更快的执行。
Apache 提供了灵活的架构,可选择不同的连接和请求处理算法。所提供的选择主要是服务器发展的结果,以及随着互联网格局的变化,对并发性的需求不断增加。
Nginx
Nginx 在 Apache 之后出现,更加关注站点在规模上面临的并发问题。因此,Nginx 从头开始设计,使用了异步、非阻塞、事件驱动的连接处理算法。
Nginx 生成工作进程,每个进程可以处理数千个连接。工作进程通过实现快速循环机制来实现这一点,该机制不断检查并处理事件。将实际工作与连接分离使得每个工作进程只在触发新事件时才关注连接。
工作进程处理的每个连接都被放置在事件循环中。在循环内,事件被异步处理,使得工作可以以非阻塞的方式进行处理。当连接关闭时,它将从循环中移除。
这种连接处理方式使得 Nginx 能够在有限的资源下扩展。由于服务器是单线程的,且不会生成进程来处理每个新连接,因此内存和 CPU 使用量在负载较重时往往保持相对稳定。
静态内容 vs 动态内容
在实际应用中,对比 Apache 和 Nginx 最常见的一个比较是它们各自处理静态和动态内容的方式。
Apache
Apache 服务器可以使用其传统的基于文件的方法处理静态内容。这些操作的性能主要取决于上面描述的 MPM 方法。
Apache 也可以通过将相应语言的处理器嵌入到每个工作实例中来处理动态内容。这使得它能够在 Web 服务器内部执行动态内容,而无需依赖外部组件。这些动态处理器可以通过使用动态可加载模块来启用。
Apache 内部处理动态内容的能力直接促成了 LAMP(Linux-Apache-MySQL-PHP)架构的流行,因为 PHP 代码可以在 Web 服务器内部原生执行。
Nginx
Nginx 本身没有处理动态内容的能力。为了处理 PHP 和其他动态内容的请求,Nginx 必须将请求交给外部库进行执行,并等待返回输出。然后可以将结果传递给客户端。
这些请求必须通过 Nginx 和外部库之间使用 Nginx 熟悉的协议之一进行交换(http、FastCGI、SCGI、uWSGI、memcache)。在实践中,PHP-FPM,一个 FastCGI 实现,通常是一个即插即用的解决方案,但实际上 Nginx 与任何特定语言的耦合程度不那么紧密。
然而,这种方法也有一些优势。由于动态解释器未嵌入工作进程中,其开销仅存在于动态内容中。静态内容可以直接简单地提供,并且只有在需要时才会联系解释器。
分布式 vs 集中式配置
Apache 和 Nginx 在允许按目录进行覆盖的方式上有显著差异。
Apache
Apache 包括一个选项,允许通过检查和解释内容目录中的隐藏文件中的指令来允许按目录进行额外配置。这些文件被称为 .htaccess
文件。
由于这些文件位于内容目录本身,处理请求时,Apache 会检查请求文件路径的每个组件是否存在 .htaccess
文件,并应用其中找到的指令。这有效地允许了 Web 服务器的分散配置,通常用于实现 URL 重写、访问限制、授权和认证,甚至缓存策略。
虽然上述示例都可以在主 Apache 配置文件中配置,但 .htaccess
文件具有一些重要优势。首先,由于每次发现它们沿着请求路径进行解释,它们会立即实施而无需重新加载服务器。其次,这使得可以允许非特权用户控制其自己的 Web 内容的某些方面,而无需控制整个配置文件。
这为某些 Web 软件(如内容管理系统)提供了一种简单的方式来配置其环境,而无需提供对主配置文件的访问。这也被共享托管提供商用于保留对主配置的控制,同时允许客户对其特定目录进行控制。
Nginx
Nginx 不解释 .htaccess
文件,也不提供在主配置文件之外评估按目录进行配置的机制。Apache 最初是在有利于在单个服务器上并行运行许多异构 Web 部署的时代开发的,委托权限是有意义的。
Nginx 是在更有可能将单个部署容器化并随其自己的网络配置一起交付的时代开发的,从而最小化了这种需求。在某些情况下,这种方法可能不如 Apache 模型灵活,但它也有其自身的优势。
与目录级配置的 .htaccess
系统相比,最显著的改进是性能提升。对于允许在任何目录中使用 .htaccess
的典型 Apache 设置,服务器将在导致请求的每个父目录中检查这些文件。如果在此搜索期间找到一个或多个 .htaccess
文件,它们必须被读取和解释。通过不允许目录覆盖,Nginx 可以通过为每个请求执行单个目录查找和文件读取(假设文件在常规目录结构中找到)来更快地提供请求。
另一个优势与安全性相关。分发目录级配置访问也将安全责任分配给个别用户,这些用户可能不被信任来处理此任务。请记住,如果这些问题与您共鸣,可以在 Apache 中关闭对 .htaccess
的解释。
基于文件 vs 基于 URI 的解释
Web 服务器如何解释请求并将其映射到系统上的实际资源是这两个服务器在另一个领域的差异。
Apache
Apache 提供将请求解释为文件系统上的物理资源或可能需要更抽象评估的 URI 位置的能力。一般来说,对于前者,Apache 使用 或
块,而对于更抽象的资源,它使用
块。
因为 Apache 是从头开始设计的 Web 服务器,所以默认情况下通常是将请求解释为文件系统资源。它从文档根目录开始,并附加主机和端口号后面的请求部分,以尝试找到实际文件。基本上,文件系统层次结构在 Web 上被表示为可用的文档树。
Apache 提供了许多替代方案,用于当请求与底层文件系统不匹配时。例如,可以使用 Alias
指令将其映射到替代位置。使用 块是一种处理 URI 本身而不是文件系统的方法。还有正则表达式变体,可用于在整个文件系统上更灵活地应用配置。
虽然 Apache 有能力在底层文件系统和其他 Web URI 上运行,但它更倾向于文件系统方法。这可以从一些设计决策中看出,包括在请求与底层文件系统镜像时警告不要使用基于 URI 的块来限制访问的 Apache 文档本身。
Nginx
Nginx 是为了同时充当 Web 服务器和代理服务器而创建的。由于这两种角色所需的架构,它主要使用 URI 进行工作,在必要时转换为文件系统。
这在 Nginx 配置文件的构造和解释方式中是显而易见的。Nginx 不提供一种指定文件系统目录配置的机制,而是解析 URI 本身。
例如,Nginx 的主要配置块是 server
和 location
块。server
块解释被请求的主机,而 location
块负责匹配主机和端口之后的 URI 部分。此时,请求被解释为 URI,而不是文件系统上的位置。
对于静态文件,所有请求最终都必须映射到文件系统上的位置。首先,Nginx 选择将处理请求的服务器和位置块,然后将文档根与 URI 结合起来,根据指定的配置进行必要的调整。
这可能看起来相似,但将请求主要解析为 URI 而不是文件系统位置,使 Nginx 能够更轻松地在 Web、邮件和代理服务器角色中发挥作用。Nginx 的配置是通过布置如何响应不同的请求模式来完成的。
Nginx 在准备服务请求之前不会检查文件系统,这就解释了为什么它不实现 .htaccess
文件的形式。
同时使用 Apache 和 Nginx
在审查了 Apache 和 Nginx 的优势和局限性之后,您可能对哪个服务器更适合您的需求有了更好的了解。在某些情况下,可以通过同时使用它们来利用每个服务器的优势。
这种合作的传统配置是将 Nginx 放在 Apache 前面作为反向代理。这将允许 Nginx 处理所有客户端请求。这利用了 Nginx 的快速处理速度和处理大量连接的能力。
对于 Nginx 擅长的静态内容,文件或其他指令将快速直接地提供给客户端。对于动态内容,例如 PHP 文件,Nginx 将代理请求到 Apache,然后 Apache 可以处理结果并返回渲染的页面。然后 Nginx 可以将内容传递回客户端。
这种设置对许多人来说效果很好,因为它允许 Nginx 充当一个分类机器。它将处理所有它能够处理的请求,并传递那些它无法本地提供的请求。通过减少 Apache 服务器被要求处理的请求,我们可以减轻 Apache 进程或线程被占用时发生的阻塞。
这种配置还通过根据需要添加额外的后端服务器来促进水平扩展。Nginx 可以配置为将请求传递给多个服务器,从而提高此配置的性能。
结论
Apache 和 Nginx 都是强大、灵活和有能力的。决定哪个服务器最适合您在很大程度上取决于评估您的具体要求,并通过测试您期望看到的模式。
这些项目之间存在差异,这些差异对原始性能、功能和在生产中使用任一解决方案所需的实施时间都有着实质性的影响。使用最符合您目标的解决方案。