Apache、Nginx 最新深度对比

刚入手一台新的MBP,在纠结搭建环境是用LAMP呢?还是LNMP呢?以下是两个服务器的对比。
连接处理架构
Apache 和 Nginx 最大的不同在于它们对连接和流量传输处理的方式 。下文将论述当它们响应不同的流量状况时,表现出的最关键的不同之处。
Apache是基于模块化设计的,它的核心代码并不多,大多数的功能都被分散到各个模块中,各个模块在系统启动的时候按需载入。


Apache中还有一个重要的组件就是APR(Apache portable Runtime Library),即Apache可移植运行库,它是一个对操作系统调用的抽象库,用来实现Apache内部组件对操作系统的使用,提高系统的可移植性。 Apache对于php的解析,就是通过众多Module中的php Module来完成的。

Apache 提供一系列多重处理模块(Multi -Processing Modules,MPM),用于指示如何处理客户端请求,Apache通过MPM来使用操作系统的资源,对进程和线程池进行管理。Apache为了能够获得最好的运行性能,针对不同的平台 (Unix/Linux、Window)做了优化,为不同的平台提供了不同的MPM,用户可以根据实际情况进行选择。大致来说,它允许管理员轻松地更换它的连接处理架构。模块如下:

  • mpm_prefork:这个处理模块产生许多单一线程的子进程,每个线程用来处理请求。每个子进程每次处理一个客户端连接。只要请求数小于进程数,MPM 是非常快的。然而,当请求数大于进程数时,性能会下降得非常快。于是在很多场景下,这不是一个好的选择。每个进程会严重影响到内存的消耗,因此 MPM 不利于有效扩展。如果结合其他不是运行在线程上的组件,这也是不错的。比如,PHP 是非线程安全的,于是多路处理模块推荐唯一安全的方法是使用 mod_php 模块来处理这些文件。

  • mpm_worker:这个模块产生许多可管理多线程的进程。每个线程能处理单个连接。这些线程比进程更高效,这意味着这个 MPM 扩展性要好于 mpm_prefork。因为线程数要多于进程数量,这也就意味着新的连接能立刻得到一个空闲的线程,而不用等待进程空闲。

  • mpm_event:这个模块在大多数场景下跟 mpm_worker 模块很相似,但是它能选择是否处理长连接(keep-alive connection)。当使用 mpm_worker 模块,为了保持连接长时间可用,于是无论请求是否是活跃的,其线程会一直被这个连接占用。这个模块保证模块能脱离长连接请求的束缚,从而更快的执行。在 Apache 2.4 版本中这个功能被标记为稳定的。

正如你所见,Apache 提供一个灵活的架构,能够选择不同的连接和请求处理算法。这些备选项主要是随着服务器演变,随着因互联网规模的改变导致请求并发量的需求增长而产生的功能。

如上图我使用brew下载的apache默认是使用prefork模式,管理者可以很轻易的切换需要的模式。

Nginx由内核和模块组成,其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。

Nginx的模块从功能上分为如下三类:

  • Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改headers信息等操作。Handlers处理器模块一般只能有一个。
  • Filters (过滤器模块)。此类模块主要对其他处理器模块输出的响应内容进行修改操作,最后由Nginx输出。
  • Proxies (代理类模块)。此类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务比如FastCGI等进行交互,实现服务代理和负载均衡等功能。

下图是nginx大致的工作流程图


Nginx 在 Apache 之后进入大众视野,它集中解决并发问题,专注于网站扩展性。随着知识进步,Nginx 使用了一种异步的,非阻塞的,事件驱动的连接处理算法进行全新设计。(下图是nginx的架构图)

Nginx 产生许多worker进程,每个进程处理上千个连接。worker进程通过实现一种快速遍历机制来持续不断地检查和处理事件,以此来完成工作。把实际工作从连接中分离出来,使得每个worker进程只需考虑它自身与从新事件触发得到的新连接。

每个连接被worker进程处理,然后跟其他连接一样被放置到事件循环中。在这个循环里,事件处理是异步的,工作是以一种非阻塞的方式进行的。当连接关闭,它就被移出了循环。

这种连接处理风格致使 Nginx 可以用有限的资源进行惊人地扩展。因为 Nginx 服务器是单线程的,并且进程不会产生子进程去处理新的连接,所以内存和 CPU 占用会相对稳定,即使是在高负载的情况下。


静态与动态内容

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

Apache 服务器使用传统的基于文件的方法来处理静态内容。这个操作的性能主要依赖上文提到的 MPM 方法的功能。

Apache 也能够处理动态内容,通过在它的每个工作实例嵌入相关语言的处理器。这使它可以在 web 服务器内部执行动态内容,而无需依赖外部组件。这些动态处理器能够通过使用动态载入模块来启动。

Apache 的动态内容处理能力意味着配置动态处理更简单了。通信不需要使用额外软件,而且如果内容需求有变化,模块可以很容易地更换。

Nginx 本身没有处理动态内容的能力。为了处理 PHP 以及其他生成动态内容的请求,Nginx 必须传递信息给外部处理器来执行,并且等待渲染内容被传输回来。最终结果将返回给客户端。

对于管理员,这意味着 Nginx 与处理器之间的通信必须配置成 Nginx 所知的协议(如 http,FastCGI,SCGI,uWSGI,memcache)。这会让事情变得略为复杂,特别是当你想要预测最大连接数的时候,因为还存在一个额外的用于调用处理器的连接。

然而,这个方法也有一些优点。因为动态解释器不内嵌在工作进程里,所以它的上游只代表动态内容。静态内容会被直接访问,所以解释器只会在需要的时候才会被调用。Apache 也能够实现这种做法,但是为了做到这样将损失上文提到的那些好处。

分布式与中心化配置

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

Apache 有一个选项,允许每个目录包含额外的配置。它从中自动检查并解析隐藏文件中的指令。这些文件被叫做 .htaccess

因为这些文件属于每个内容目录,所以当处理一个请求时,Apache 会检查请求文件路径中的每个部分,为了执行 .htaccess 文件里面的指令。这使 web 服务器有效进行去中心化的配置,通常被用来实现修改 URL,访问限制,授权和验证,甚至缓存策略。

然而以上所说的可以全部写在 Apache 的主配置文件中,.htaccess 文件有许多重要的特性。首先,由于它每次根据请求路径来解析文件,所以无需重启服务器就可以立刻生效配置。其次,它允许未授权用户部分控制他们自己的网络内容,而无需给他们操作整个配置文件的权限。

这对于一些网络软件来说是个很轻松的方法。比如内容控制系统(CMS),无需访问中心配置文件就能够调整它们的环境配置。这也能让共享主机提供商保留主配置的控制权的同时,让客户去操作他们自己的独立目录。

Nginx 不会解析 .htaccess 文件,也不会提供类似机制去处理脱离主配置文件的各个目录配置。相比 Apache 模型这样少了很多灵活性,但是它有自己的优势。

相对于 .htaccess 系统的目录级别配置,Nginx 最值得注意的改进是性能提升。传统的 Apache 服务器设置允许在于任何目录下设置 .htaccess 文件。于是每次请求时,服务器会在被请求文件的每个父目录下查找这些文件。如果发现了一个或多个 .htaccess 文件,它们一定会被读取并被解析。而 Nginx 并不允许目录覆盖,它通过在唯一的目录下查找匹配,读取文件——假设这个文件是在传统目录架构下的——来更快地响应请求。

另一个优势是相对安全。分布式目录式配置访问的同时也把安全职责分布给了每个独立用户,这些用户也许不能可靠地处理好任务。保证管理员维护整个 web 服务器,能防止一些因为把权限交给别人而引发的安全疏漏。

请记住,如果你担心那些安全隐患,你也可以让 Apache 停止解析 .htaccess

文件与基于 URI 的解析

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

Apache 可以将一个请求解析为文件系统中的一个物理资源,或者一个需要更多抽象计算的 URI 地址。通常对于前者,Apache 使用 <Directory> 或者 <Files> 块,其利用 <Location> 块来代表更多抽象资源。

因为 Apache 完全被设计成一种 web 服务器,默认就是把请求解析为文件系统资源。一开始它表示一个文件根节点,然后在其末尾增加请求的主机和端口部分,用来查询一个真实文件。总的来说,文件系统的分层结构在网络上体现为一个可访问的文件树。

当请求没有匹配到文件,Apache 提供一系列可选项。比如,Alias 命令能够用来映射到一个可选的地址。使用 <Location> 块可以作为 URI 的访问方法来代替文件系统。还可以使用正则表达式变体通过文件系统让配置变得更加灵活。

尽管 Apache 有能力去操作文件系统和网络空间,它还是重度依赖于文件系统的操作方法。这在一些设计决策得以体现,包括使用 .htaccess 文件来配置每个目录。Apache 文档里提醒到,当镜像请求底层文件系统时,使用基于 URI 的块来限制访问。


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 的英文文档十分困难。因为大多数早期开发以及文档都是用俄语完成的。随着项目受到更多关注,文档得以填补,现在在 Nginx 官网上和第三方组织上有许多管理资源。

对于第三方应用,技术支持和说明文档正变得更加可用。有一些项目,包维护者开始给出两个选项,用于自动化配置 Apache 或者 Nginx。即使没有支持,只要项目自身说明了要求(许可,头信息等等),就可以直接配置 Nginx 与其他软件一起工作。

同时使用 Apache 和 Nginx

在浏览过 Apache 和 Nginx 的各种优势与限制之后,你也许对使用哪个服务器更符合你的需求有了更好的主意。然而,许多用户发现也许可以权衡两者,让它们共同发挥各自的威力。

传统使用它们的方法,是将 Nginx 作为反向代理放在 Apache 前面。这将使 Nginx 处理所有客户端请求。充分利用 Nginx 快速响应的优势,以及它处理大量并发连接的能力。(配置详情见我之前的博客)

对于静态内容,Nginx 擅长快速将文件直接返回给客户端。对于动态内容,比如 PHP 文件,Nginx 将把请求转发给 Apache,Apache 处理好后把渲染好的页面返回。Nginx 再将结果返回给客户端。

这种配置对于许多用户来说运作良好。因为它将 Nginx 作为一个排序机器,处理所有请求,然后将它本身难以处理的请求传递给 Apache。通过减少给 Apache 服务器的请求,我们能够缓解一些 Apache 进程或者线程发生阻塞的情况。

这种配置让你能够通过增加必要的后端服务器来横向扩展。Nginx 能够轻松地配置成传递请求给服务器集群。以此增强配置来抵御故障,提高性能。

结论

如你所见,Apache 和 Nginx 都是很强力、灵活、能干的。决定哪个服务器对你来说最好,主要取决于什么功能可以解决你的特定需求,然后用你的方式去测试它。

这两个项目在原生性能、功能,以及启动和运行每个解决方案所需的必要时间上有非常现实的冲突。然而,这些都是一系列取舍后的结果,不应该不假思索地随意使用。最后,没有通用的适合所有场景的 web 服务器,所以选择最切合你的目标的解决方案吧。


参考文章:http://yansu.org/2014/02/15/apache-and-nginx.html

               http://adoyle.me/blog/apache-vs-nginx-practical-considerations.html



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值