Apache vs Nginx:基于实践经验的比较(外文翻译)

372 阅读18分钟

本文来自Mobingi官方技术专栏,欢迎关注

原文地址:Apache vs Nginx: Practical Considerations

简介

Apache和Nginx是世界上两个最流行的开源web服务器,他们一起支撑了互联网上超过50%流量。他们两个都支持多种负载模式并且可以和其他软件服务集成在一起提供全栈的web解决方案。

虽然Apache和Nginx有很多共同点,但你不应该认为它们是可以完全等价交换的。它们都·有自己各自的长处,了解这些有助于你重新评估你的web服务器的选择。这篇文章致力于讨论这两个服务器在不同领域的不同表现。

概览

在我们深入讨论Apache和Nginx的不同之前,让我们先简单回顾一下这两个项目的背景和特性。

Apache

Apache HTTP 服务器于1995年由Robert McCool在Apache软件基金会(1999创立)的领导下开发出来。因为它是这个基金会的原创项目并且也是这个基金会到目前为止最有名的软件,所以它经常被称做“Apache”。

Apache从1996年开始直到现在一直是互联网上最流行的web服务器软件。因为流行,Apache基金会可以通过提供完善的文档以及系统集成支持给其他软件项目来获取收益。

因为Apache的灵活性,性能和广泛支持,它经常被系统管理员选择作为web服务器。它可以通过动态加载模块拓展功能,并且可以在不连接其他第三方软件的情况下执行多种解释型语言。

Nginx

在2002年,Igor Sysoev开始着手写Nginx服务器用来解决C10K问题。C10K问题是web服务器的一个挑战,要求一个web服务器在同一时刻可以处理10000个连接请求。Nginx于2004年发布最新版本,使用一种非同期的、基于事件处理机制来满足这一需求。

因为占用很少资源并且非常容易使用底端硬件扩展,Nginx开始变得流行。Nginx擅长提供静态内容,并且被设计为将需要动态内容处理的求转发给其他软件以解决10K问题。

Nginx经常由于它的低资源消耗以及高负载能力被服务器管理员选中,它的拥护者非常欢迎Nginx聚焦在web服务器以及代理服务器的核心特性上。

连接处理方式

Apache和Nginx的一个巨大的差距是他们实际处理连接和请求的方式。在不同的网络流量条件下,这产生了两个服务器非常不同的表现。

Apache

Apcahe提供了多种多进程工作模式(Apache称这些为MPMs, multi-processing modules)来处理请求,基本上,这样可以让管理员很容易地变换服务器处理连接的方式。这些模式如下:

  • mpm_prefork:这种模式为每一个请求创建一个处理它的进程。每个子进程同一时间只处理一个请求。如果请求数量小于进程数量,这种模式运行的非常快。不过当需要处理请求超出进程数量时,性能下降非常严重,所以对于很多应用场景这种模式不是一个好的选择。每一个进程都会耗损相当的内存,所以这种工作模式很难优化。当处理请求的内部组件不支持线程工作模式的情况下,这种模式可能仍然是一个好的选择。比如,PHP就不是线程安全的,所以这种工作模式被推荐为与mod_php一起运行的唯一安全模式。

  • mpm_worker: 这种模式创建的进程可以管理自己线程。每一个线程可以单独处理一个连接。因为与进程相比系统可以创建更非常多的线程,也就意味着这种模式比prefork模式能处理更多的连接。一个新的连接会被马上处理,而不需要等待一个空闲的进程来处理。

  • mpm_event: 这种模式和worker模式很像,不过它优化了keep-alive请求的处理方式。当使用worker模式的时候,一个连接(connection)会持有一个线程直到这个连接失效,不管这个连接上是否有请求过来。在event模式下,有专门的线程用来处理和保持连接,然后将请求转发给其他线程处理。这种方式可以让系统逃脱处理大量keep-alive请求的泥潭,使请求处理器得到更快的执行。这个模式在Apache2.4版本中已被标记为稳定(stable)状态。

就像你看到的,Apache提供了一个灵活的结构可以配置不同的连接和请求处理算法。这些工作模式代表了服务器的功能演进以及伴随着互联网格局变化而来的对大并发处理的需求的增长。

Nginx

Nginx在Apache之后来到这个舞台,与生俱来就意识到需要面对大并发问。利用这方面的认识,Ngeix彻底地由内到外地使用了非同期,非阻塞和事件驱动的连接处理算法。

Nginx生成工作进程,每一个工作进程可以处理上千个连接。工作进程通过实现一个快速的循环算法不断的获取并处理事件。从连接中分离出实际的请求处理工作,让每一个工作进程只有当新的事件发生是才与一个连接产生联系。

所有被工作进程处理的连接被放在事件循环(event loop)里面,在这个循环里,事件被非同期处理,使得处理变成一个非阻塞的过程。当连接关闭,连接从这个循环中删除。

这种连接方式使得Nginx可以利用有限的计算资源处理不可思议的大量请求。因为服务器是单线程的并且并不为处理一个新的连接生成一个单独的进程,所以内存和CPU的消耗趋于保持相对一致,甚至是在大并发的情况下也如此。

静态内容VS动态内容

在实际应用方面,Apache和Nginx之间最常见的比较是但请求到来时它们各自处理静态内容和动态内容的方式。

Apache

Apache使用传统的基于文件的方式处理静态内容的请求。它的性能主要取决于它是被设定成哪工作模式(上面提到的)。

Apache也可以处理动态内容,它通过嵌入一种处理语言到运行实例,在服务器内部就可以处理动态内容,而不需要依赖外部组建。它通过使用可动态加载的模块来开启处理动态内容的进程。

Apache的可在服务器内部处理动态内容的能力意味着配置动态处理进程也比较简单。不需要和一个附加的软件交互并且当内容处理的需求发生变化时模块也很容易替换。

Nginx

Ngnix本身没有任何的动态处理能力。如果想执行PHP代码或者为请求生成动态内容,Nginx必须将请求传递给一个外部的处理器并等待渲染好的内容(通常是HTML文档)然后再把它转发给客户端。

对于服务器管理员来说,这个意味着你必须配置Nginx和外部处理器之间的交互,这种交互必须基于一种Nginx能理解的协议(http, FastCGI, SCGI, uWSGI, memcache)。这可能会使事情变得稍微复杂,特别是试图占用允许连接的最大值时,因为已有了一个额外的连接用来转发请求到处理器。

不管怎么说,这个模式同时也有一些优点。因为动态解释器不是嵌入到Nginx的工作进程中的,所以它的开销只限于处理动态内容,而静态内容请求会被直接处理,Nginx只在需要的时候连接程序解释器。Apache也可以这样工作,不过这样的话就失去了我们在前面说的优点。

分布式配置VS集中配置

对于服务器管理员来说,两个服务器表现出来的最明显的不同是是否允许文件夹级别的配置。

Apache

apache提供一个选项,允许对每个目录设置附加的配置。这个功能基于监测和实时翻译内容所在文件夹上一个隐藏文件中的指令来完成。这个文件就是大家所熟知的.htacess。

因为.htacess文件就存在于请求内容所在文件夹。当处理一个请求的时候,Apache检查每一个文件的路径,查找.htacess文件,执行里面的命令,这使服务器的分散配置成为可能。这个功能经常用于重写URL,控制访问甚至是缓存策略。

虽然上面说的例子可以在Apache的主配置文件中设置。但是.htacess有一些重要的优势。首先,Apache在每次请求来的时候解释指令,所以.htacess的配置会立即生效,而无需重启服务器。其次它允许无权限的用户来控制他们自己的web内容的某些方面,而无需修改Apache主配置文件。

这给某些web软件,如内容管理系统(cms)提供了简单方式来配资它们自己,而无需访问主配置文件。这也同样被用于共享主机提供商使他们在保持控制主要配置文件的同时让客户对他们自己的特定目录有控制权限。

Nginx

nginx不会即时解释.htacess文件,也不提供在主配置文件之外的任何支持目录级别配置的技术。这可能相对于apache来说不够灵活,但它却有自己的优势。

最被大家熟知的相对于基于.htacess机制实现目录级别配置的系统优势就是提高了性能。例如一个典型的Apache配置可能允许配置.htaccess在任何目录,这样的话每一个请来访问任何一个目录下的资源的时候,服务器都会检查这个目录以及它所有的父目录的.htaccess文件,如果在这个过程中有一个或者多个.htaccess文件被找到,他们必须被读取并解释执行。Nginx不允许目录重写技术,每一个请求过来Nginx只查找和读取一个文件(假设文件可以在约定目录结构下找到),所以Nginx处理请求更快。

另一个优势是关于安全的。分散的目录级别的配置也同时把安全配置web服务的责任分散到了每一个用户(web应用管理员)头上,他们可能无法胜任这个任务。确保服务器管理员控制整个web服务器可预防一些把控制权转交给他人所造成的安全隐患。

如果这些观点与你产生共鸣,你应该时刻考虑是否可以关闭解释执行.htaccess文件。

文件VS基于URI的解释执行

web服务器是如何解释执行一个请求以及如何查找到与请求所匹配的系统资源的?这是另一个这两个服务器的不同之处。

Apache

Apache提供一种可以把请求转换成文件系统上的物理资源或者一个更抽象的URI的能力。总体上,以前的Aapache使用 或者块配置,同时使用块配置更抽象的资源。

因为Apache完全是为web服务器所设计。默认情况下一个请求通常被解释成一个文件资源请求。它在查找请求路径中去掉域名和端口号后相对于document root的路径下的真实文件。默认情况下,文件结构会被以文档树的形式展示。

当请求没有匹配到文件资源时,Apache提供很多可选项处理这种情况。比如,一个alias命令可以让请求关联到另一个位置。用块可以使用URI代替文件系统工作。当然还可以使用正则表达式,从而使基于文件系统的资源查找更加灵活。

虽然Apache同时具有操作底层文件系统和网站空间的能力,但是它非常依赖于文件系统,包括使用.htacces文件实现目录级配置这,都可以被看作它的设计哲学。Apache docs警告用户当请求可以映射到底层文件系统时,最好不要使用基于URI的配置限制访问。

Nginx

Nginx被当做web服务器和代理服务器而创造。考虑这两种角色所需要的架构,它主要基于URI工作。只在需要的时候在将请求映射到文件系统。这可以被看作是构造和解释执行Nginx配置的方式。Nginx不提供任何关于文件系统目录的配置,取而代之的是解析URI本身。

举个例子,Nginx主要的配置块是server和location块。server配置块用来解释请求的域名部分,同时location配置块负责匹配URI中域名和端口号后面的的部分。从这个观点看,请求被解释成一个URI请求,并不是一个映射到文件系统上的文件。

对于静态文件,所有的请求最终会映射到文件系统上的一个文件。首先,Nginx找到用于处理这个请求的server配置块和location配置块,然后组合document root目录和URI,再根据指定配置做任何必要的调整。

这可能看起来很简单,但是解析请求成URI而不是文件系统路径使得Nginx能跟简单地以web、mail和代理服务器方式工作,通过简单的配置就以对应不同模式的request请求。Nginx不会检查文件系统直到准备好提供被请求的内容,这解释了为什么它没有实现一种类似.htaccess的配置方式。

模块

Nginx和Apache都支持通过模块扩展服务器,但是他们的工作方式非常的不同。

Apache

Apache的模块系统允许你在服务器的运行期间动态的加载或者卸载模块。Apache的核心始终存在,而模块可以打开或关闭,以添加或者删除挂载到server的主程序部分的附加功能。Apache通过这一个功能完成很多任务。由于Apache平台非常成熟,有很多用于扩展Apache的模块存在。他们可以用于改变Apache的一部分核心功能,例如mod_php就可以嵌入PHP处理器到每一个运行的工作进程中。

模块不仅仅只限于处理动态内容,它们还被用于URL重写,认证客户端,硬件化服务器,日志,缓存,压缩,代理,速率控制和编码等等。动态模块可以很容容易的扩展核心功能并且并不需要太多额外的工作。

Nginx

Nginx也实现了一个模块系统,但是它与Apache的实现方式很不同。在Nginx中,模块不是动态加载的,它们必须被编译到Nginx的核心程序中。

对于很多用户来说,这可能让他们感觉Nginx不够灵活。尤其对那些只会安装发布版本而不熟悉通过编译来管理维护自己软件的用户来说,这确实是一个问题。不过发布版本总是倾向于包含使用最广泛的模块,如果你需要一个非标准的模块,你必须要自己编译你的Nginx服务器软件。

编译Nginx的模块还是非常有用的,他们允许指出哪些功能你不想放在服务器中,而哪些功能你需要使用。很多用户也认为这样更加安全,因为那些未经挑选的组件不会挂载到服务器中。不管怎样,如果你的服务器已经配置好了,它很可能是妥协后的产物。

Nginx模块的功能很多都和Apache模块相似。例如,Nginx模块可以提供代理服务,压缩,速率控制,日志,重写,地理位置,认证,编码,流媒体和邮件功能。

支持、兼容性、生态系统和文档

考虑这些的要点在于,你的应用主要做什么样的处理,需要配合哪些其他软件使用。

Apache

因为Apache已经流行了很长时间,对它的支持几乎是普遍存在的。有很多官方的或者第三方的文档说明核心服务器以及如何挂载其他软件到核心服务器。

Nginx

因为Nginx的高性能,越来越多的用户选择使用Nginx,越来越来越多的软件开始支持Nginx。但是在很多关键领域Nginx还需要追赶Apache的脚步。

在过去,找到一份全面的关于Nginx的文档很难。因为大部分早期的开发是由俄罗斯人完成,文档也是俄语的。伴随着这个项目的普及,产生了很多文档,并且在Nginx的网站以及第三方站点上有非常多的管理员资源。

出于对第三方软件的尊重,技术支持文档变得更加易读,并且Nginx软件包维护者开始在某些情况下允许Apache和Nginx之间配置的自由转换。就算没有技术支持,配置Nginx服务器和可选软件一起工作也通常非常简单直接,正如它项目文档里描述的那样。

Apache和Nginx一起使用

在我们了解了Apache和Nginx的优势和劣势之后,你可能已经想好了哪一个服务器更符合你的需求。无论如何,很多用户发现可以通过同时使用它们而获得它们两个的所有优点。

这种组合的传统配置是把Nginx配置到Apache的前端作为一个反向代理服务器。这使Nginx处理来自客户端的所有请求。这样得益于Nginx的快速处理能力,可以同时处理非常大量的连接。

对于Nginx擅长静态内容,文件会快速且直接的发送给客户端。对于动态内容,比如PHP文件,Nginx将把请求发送给Apache,Apache可以处理请求,并渲染结果。然后Nginx可以将结果发回给客户端。

这种设置在大多数情况下都工作的很好。因为这让Nginx像一台排序机器一样工作,Nginx会处理所有的请求然后把它不能处理的请求转发出去,通过减少Apache处理的请求数量,可以缓解当Apache的处理进程或者线程被占用时产生的阻塞。

这样配置也使你可以根据需求添加额外的后端服务器来扩容服务器。Nginx可以很容易的配置成转发请求到服务器池,这样可以增强服务器性能和容错能力。

总结

正如你看到的,Apache和Nginx都是强大,灵活的服务器软件。哪个服务器最好,取决于你的应用服务的特殊需求,以及对它们在你期望的运行条件下的测试结果。

在两个服务器之前存在着很多不同,这些差异的存在会实实在在地影响性能,负载,以及配置应用运行起来的时间成本。然而,这是一系列权衡结果,不应该被随意决定。最后我要说,没有万能的web服务器,所以选择适合你的项目的解决方案。


这是我第一次翻译英文文档,很多词汇找不到合适的中文表达,也可能有一些专业技术词汇没有和中文技术词汇精确对应,请大家多多指正。