Apache与Nginx实际比较

介绍

Apache和Nginx是世界上最通用的两大开源Web服务器。他们正为超过50%互联网流量传输提供服务。两种解决方案都能处理各种的工作场景,并与其他软件协同工作,从而提供完善的Web技术栈。
尽管Apache和Nginx有许多共通的特性,并不能将它们视为可以完全相互替代的。它们各有所长。了解使用场景对你重新评估选择你的Web服务器非常重要,这篇文章将专注于讨论两种服务器如何应对不同场景。

概述

在深入比较Apache和Nginx之前,让我们快速浏览一下这两个项目各自的背景和特点。

  • Apache
    Apache HTTP服务器由Rebert McCool在1995年创建,并从1999年开始在Apache软件基金会的指挥下进行开发。由于这个HTTP web服务器是基金会的原始项目,并且到目前为止也是他们最流行的软件之一,于是常常将它简称为“Apache”。
    自从1996年,Apache web服务器就已经是互联网上最流行的服务器了。正因为如此普及,Apache从丰富的文章中受益,并被许多其他软件项目集成支持。
    之所以管理员选择使用Apache,是因为它的灵活、高效以及广泛的支持。它通过一个动态加载模块系统来实现可扩展,并且能在不连接外部软件的情况下,独自处理大量解释型语言。
  • Nginx
    在2002年,Igor Sysoev开始研发Nginx来解决C10k问题--在当时需要web服务器同时处理一万个连接以应对现代网络的需求--这是一个艰难的跳转。它的首个公开版本发布是在2004年,通过异步的事件驱动架构得以实现目标。
    得益于它的轻量级资源利用,和它在简单硬件设施上的扩展能力,Nginx自从发布后日益流行。Nginx擅长于快速处理静态内容,并且它被设计为可向其他软件传递动态请求,这更符合它的开发目的。
    之所以管理员们选择使用Nginx,是因为它的资源利用度以及负载时的响应能力。Nginx的拥护者欣赏它专注于web服务器的核心以及它的代理特性。

连接处理架构

Apache和Nginx最大的不同在于它们对连接和流量传输处理的方式。下文将论述当它们响应不同的流量状况时,表现出的最关键的不同之处。

  • Apache
    Apache提供一系列多路处理模块(Apache称这些为MPMs),用于指示如何处理客户端请求。大致来说,它允许管理员轻松地更换它的连接处理架构。模块如下:
    • mpm_prefork:这个处理模块产生许多单一线程的子进程,每个线程用来处理请求。每个子进程每次处理一个客户端连接。只要请求树小于进程数,MPM是非常快的。然而,当请求数大于进程数时,性能会下降得非常快。于是在很多场景下,这不是一个好的选择。每个进程会严重影响到内存的消耗,因此MPM不利于有效扩展。如果结合其他不是运行在线程上的组件,这也是不错的。比如,PHP是非线程安全的,于是多路处理模块推荐唯一安全的方法是使用mod_php模块来处理这些文件。
    • mpm_worker:这个模块产生许多可管理多线程的进程。每个线程能处理单个连接。这些线程比进程更高效,这意味着这个MPM扩展性要好于mpm_prefork。因为线程数要多于进程数量,这也就意味着新的连接能立刻得到一个空闲的线程,而不用等待进程空闲。
    • mpm_event:这个模块在大多数场景下跟mpm_worker模块很相似,但是它能选择是否处理长连接(keep-alive connection)。当使用mpm_worker模块,为了保持连接长时间可用,于是无论请求是否是活跃的,其线程会一直被这个连接占有。这个模块保证模块能脱离长连接请求的束缚,从而更快的执行。在Apache2.4版本中这个功能被标记为稳定的。
      正如你所见,Apache提供了一个灵活的架构,能够选择不同的连接和请求处理算法。这些备选项主要是随着服务器演变,随着因互联网规模的改变导致请求并发量的需求增长而产生的功能。
  • Nginx
    Nginx在Apache之后进入大众视野,它集中解决并发问题,专注于网站扩展性。随着知识进步,Nginx使用了一种异步的,非阻塞的,事件驱动的连接处理算法进行全新设计。
    Nginx产生许多工作进程,每个进程处理上千个连接。工作进程通过实现一种快速遍历机制来持续不断地检查和处理事件,以此来完成工作。把实际工作从连接中分离出来,使得每个工作进程只需考虑它自身与从新事件触发得到的新连接。
    每个连接被工作进程处理,然后跟其他连接一样被放置到事件循环中。在这个循环里,事件处理是异步的,工作室以一种非阻塞的方式进行的。当连接关闭,它就被移出了循环。
    这种连接处理风格致使Nginx可以用有限的资源进行惊人地扩展。因为Nginx服务器是单线程的,并且进程不会产生子进程去处理新的连接,所以内存和CPU占用会相对稳定,即使是在高负载的情况下

静态和动态内容

以真实世界的案例来说,最通常比较的是Apache和Nginx如何处理静态和动态内容的请求。

  • Apache
    Apache服务器使用传统的基于文件的方法来处理静态内容。这个操作的性能主要依赖上文提到的MPM方法的功能。
    Apache也能够处理动态内容,通过在它的每个工作实例嵌入相关语言的处理器。这使它可以在web服务器内部执行动态内容,而无需依赖外部组件。这些动态处理器能够通过使用动态载入模块来启动。
    Apache的动态内容处理能力意味着配置动态处理更简单了。通信不需要使用额外软件,而且如果内容需求有变化,模块可以很容易地更换。
  • Nginx
    Nginx本身没有处理动态内容的能力。为了处理PHP以及其他生成动态内容的请求,Nginx必须传递信息给外部处理器来执行,并且等待渲染内容被传输回来。最终结果将返回给客户端。
    对于管理员,这意味着Nginx与处理器之间的通信必须配置成Nginx所知的协议(如http、FastCGI、SCGI、uwSGI、memcache)。这会让事情变得略为复杂,特别是当你想要预测最大连接数的时候,因为还存在一个额外的用于调用处理器的连接。
    然而,这个方法也有一些优点。因为动态解释器不内嵌在工作进程里,所以它的上游只代表动态内容。静态内容会被直接访问,所以解释器只会在需要的时候才会被调用。Apache也能够实现这种做法,但是为了做到这样将损失上文提到的那些好处。

分布式与中心化配置

对于管理员,两个软件间最显而易见的不同是内容目录中是否允许目录级别的配置。

  • Apache
    Apache有一个选项,允许每个目录包含额外的配置。它从中自动检查并解析隐藏文件中的指令。这些文件被叫做.htaccess。
    因为这些文件属于每个内容目录,所以当处理一个请求时,Apache会检查请求文件路径中的每个部分,为了执行.htaccess文件里面的指令。这使web服务器有效进行去中心化的配置,通常被用来实现修改URL,访问限制,授权和验证,甚至缓存策略。
    然而以上所说的可以全部写在Apache的主配置文件中,.htaccess文件有许多重要的特性。首先,由于它每次根据请求路径来解析文件,所以无需重启服务器就可以立刻生效配置。其次,它允许未授权用户部分控制它们自己的网络内容,而无需给他们操作整个配置文件的权限。
    这对于一些网络软件来说是个很轻松的方法。比如内容控制系统(CMS),无需访问中心配置文件就能够调整它们的环境配置。这也能让共享主机提供商保留主配置的控制权的同时,让客户去操作他们自己的独立目录。
  • Nginx
    Nginx不会解析.htaccess文件,也不会提供类似机制去处理脱离主配置的各个目录配置。相比Apache模型这样少了很多灵活性,但是它有自己的优势。
    相对于.htaccess系统的目录级别配置,Nginx最值得注意的改进是性能提升。传统的Apache服务器设置允许在于任何目录下设置.htaccess文件。于是每次请求时,服务器会在被请求文件的每个父目录下查找这些文件。如果发现一个或多个.htaccess文件,它们一定会被读取并被解析。而Nginx并不允许目录覆盖,它通过在唯一的目录下查找匹配,读取文件--假设这个文件是在传统目录架构下的--来更快地响应请求。
    另一个优势是相对安全。分布式目录式配置访问的同时也把安全职责分布给了每个独立用户,这些用户也许不能可靠地处理好任务。保证管理员维护整个web服务器,能防止一些因为把权限交给别人而引发的安全疏漏。
    请记住,如果你担心那些安全隐患,你也可以让Apache停止解析.htaccess。

文件与基于URI的解析

Web服务器如何解析请求并将它们映射到系统实际资源,是比较两个服务器的另一重点。

  • Apache
    Apache可以将一个请求解析为文件系统中的一个物理资源,或者一个需要更多抽象计算的URI地址。通常对于前者,Apache使用<Directory>或者<Files>块,其利用<Location>块来代表更多抽象资源。
    因为Apache完全被设计成一种Web服务器,默认就是把请求解析为文件系统资源。一开始它表示一个文件根节点,然后在其末尾增加请求的主机和端口部分,用来查询一个真实文件。总的来说,文件系统的分层结果在网络上体现为一个可访问的文件树。
    当请求没有匹配到文件,Apache提供一系列可选项。比如,Alias命令能够用来映射到一个可选的地址。使用<Location>块可以作为URI的访问方法来代替文件系统。还可以使用正则表达式变体通过文件系统让配置变得更加灵活。
    尽管Apache有能力去操作文件系统和网络空间,它还是重度依赖于文件系统的操作方法。这在一些设计决策得以体现,包括使用.htaccess文件来配置每个目录。Apache文档里提醒到,当镜像请求底层文件系统时,使用基于URI的块来限制访问。
  • Nginx
    Nginx被设计为web服务器和代理服务器。由于这两个架构要求,Nginx主要使用URI工作,在必要时可以将它映射到文件系统上。
    这体现在一些nginx配置文件的构造与解析中。Nginx没有提供可以给特定文件目录指定配置的机制;相对的,它能够解析URI。
    例如,Nginx的主配置是server和location块。当location块匹配到URI主机和端口后面的部分,server块就用来解析被请求的主机。在这时,请求被解析为URI,而不是文件系统的地址。
    对于静态文件,所有请求最终会被映射到文件系统上的地址。首先,Nginx选择一个服务器和地址块来处理请求,然后将文件根节点绑定到这个URI上,根据配置文件所指示的修改某些东西。
    这也许似曾相识,不过却是主要使用URI而不是文件地址来解析请求,这样使得Nginx更容易实现web服务器、邮件服务器以及代理服务器的角色。通过列出如何响应不同的请求模式,让Nginx配置起来很简单。在Nginx准备好去处理某个请求前,它不会去检查文件系统,这解释了为什么它不实现.htaccess这种形式的文件。

模块

Nginx和Apache都可以通过模块系统进行扩展,但是它们的运作方式是完全不同的。

  • Apache
    Apache的模块系统允许你动态加载或拆卸模块,以保证在服务器运行时满足你的需求。当模块被开启或关闭时,当附属功能挂载到主服务器或者从主服务器移除时,Apache内核是始终运行着的。
    Apache使用这个功能实现了大量复杂的任务。因为这个系统已发展成熟,所以有丰富的模块库可供使用。你也可以使用模块来改写一些核心功能。比如mod_php,这个模块用来给正在运行中的工作进程内嵌PHP解释器。
    然而模块没有限制处理动态内容。在其他功能中,它们可以被用来重写URL,验证客户端,加强服务器,日志,缓存,压缩,代理,限流,加密。动态模块能扩展核心功能而无需顾虑太多额外工作。
  • Nginx
    Nginx也实现了模块系统,但是它与Apache系统非常不一样。在Nginx中,模块不是动态加载的,因此必须事先选择好并将它们编译到核心软件中。
    对于许多用户来说,这降低了Nginx的灵活度,尤其是对那些不负责编译软件的用户来说。因为分发的包通常只包含通用的模块,如果你想要使用非标准的模块,就不得不自己编译源码来构建服务器。
    尽管如此,Nginx模块依然非常有用,你可以自己决定在你的服务器之外加载任何想要的功能。有些用户也许更在意安全性,因为组件不应该随意地挂载到服务器上。然而,如果你曾经把服务器放在一个可以随意挂载的机器上,那么它可能已经受到了损害。
    Nginx模块拥有许多同Apache模块一样的能力。例如,Nginx模块支持代理,压缩,限流,日志,重写,地理位置,验证,加密,流式处理,以及邮件功能。

技术支持,兼容性,生态系统,以及文档

重点要考虑的是启动和运行过程中,其他软件的支持程度,以及可以获得多大帮助。

  • Apache
    因为Apache流行已久,对于它的支持是相当普遍的。有大量的官方库,有解释服务器内核的第三方文档,还有根据具体业务场景去结合其他软件调用Apache的第三方文档。
    随着文档的普及,许多工具和web项目包含了能将自己部署在Apache环境下的启动工具。这些可能就包含在项目里,亦或你的分发打包团队把它维护在工具包里。
    因为它的市场分享以及经过长时间的考验,Apache通常会从第三方项目中得到更多支持。管理员更愿意选择使用Apache进行工作,不仅仅是因为它的流行度,还因为.htaccess分布式管理的能力,让很多人在一开始就完全依赖Apache来实现主机共享的场景。
  • Nginx
    随着更多用户调整配置Nginx的性能,它的支持体验也正在提升,但在某些领域它仍有许多事情要做。然而,许多用户发现也许可以权衡两者,让它们共同发挥各自的威力。
    传统使用它们的方法,是将Nginx作为反向代理放在Apache前面。这将使Nginx处理所有客户端请求。充分利用nginx快速响应的优势,以及它处理大量并发连接的能力。
    对于静态内容,Nginx擅长快速将文件直接返回给客户端。对于动态内容,比如PHP文件,Nginx将把请求转发给Apache,Apache处理好后把渲染好的页面返回。Nginx再将结果返回给客户端。
    这种配置对于许多用户来说运作良好。因为它将Nginx作为一个排序机器,处理所有请求,然后将它本身难以处理的请求传递给Apache。通过减少给Apache服务器的请求,我们能够缓解一些Apache进程或者线程发生阻塞的情况。
    这种配置让你能够通过增加必要的后端服务器来横向扩展。Nginx能够轻松地配置成传递请求给服务器集群。以此增强配置来抵御故障,提高性能。

结论

如你所见,Apache和Nginx都是很强力、灵活、能干的。决定哪个服务器对你来说最好,主要取决于什么功能可以解决你的特定需求,然后用你的方式去测试它。
这两个项目在原生性能、功能,以及启动和运行每个解决方案所需的必要时间上有非常现实的冲突。然而,这些都是一系列取舍后的结果,不应该不假思索地随意使用。最后,没有通用的适合所有场景的web服务器,所以选择最切合你的目标的解决方案吧。

推荐阅读更多精彩内容