不断有人跟我说Nginx比Apache好、比Apache快之类。Nginx更主要是作为反向代理,而非Web服务器使用。我翻译过一本关于反向代理的技术书籍,同时精通Apache API开发,对Nginx和Apache的工作原理都略有了解,粗谈一下看法。
不管是Nginx还是Squid这种反向代理,其网络模式都是事件驱动。事件驱动其实是很老的技术,早期的select、poll都是如此。后来基于内核通知的更高级事件机制出现,如libevent里的epoll,使事件驱动性能得以提高。事件驱动的本质还是IO事件,应用程序在多个IO句柄间快速切换,实现所谓的异步IO。事件驱动服务器,最适合做的就是这种IO密集型工作,如反向代理,它在客户端与WEB服务器之间起一个数据中转作用,纯粹是IO操作,自身并不涉及到复杂计算。反向代理用事件驱动来做,显然更好,一个工作进程就可以run了,没有进程、线程管理的开销,CPU、内存消耗都小。
所以Nginx、Squid都是这样做的。当然,Nginx也可以是多进程 + 事件驱动的模式,几个进程跑libevent,不需要Apache那样动辄数百的进程数。Nginx处理静态文件效果也很好,那是因为静态文件本身也是磁盘IO操作,处理过程一样。至于说多少万的并发连接,这个毫无意义。我随手写个网络程序都能处理几万的并发,但如果大部分客户端阻塞在那里,就没什么价值。
再看看Apache或者Resin这类应用服务器,之所以称他们为应用服务器,是因为他们真的要跑具体的业务应用,如科学计算、图形图像、数据库读写等。它们很可能是CPU密集型的服务,事件驱动并不合适。例如一个计算耗时2秒,那么这2秒就是完全阻塞的,什么event都没用。想想MySQL如果改成事件驱动会怎么样,一个大型的join或sort就会阻塞住所有客户端。这个时候多进程或线程就体现出优势,每个进程各干各的事,互不阻塞和干扰。当然,现代CPU越来越快,单个计算阻塞的时间可能很小,但只要有阻塞,事件编程就毫无优势。所以进程、线程这类技术,并不会消失,而是与事件机制相辅相成,长期存在。
总结之,事件驱动适合于IO密集型服务,多进程或线程适合于CPU密集型服务,它们各有各的优势,并不存在谁取代谁的倾向。再盲目的言之Nginx可以取代Apache的,该好好反思了。
参考文献2:http://bbs.chinaunix.net/thread-3776844-1-1.html
Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,将Perl/Python等解释器编译到服务器中。
Nginx是十分轻量级的HTTP服务器,是一个高性能的HTTP和反向代理服务器,Nginx以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。
可以说,Apache 和 Nginx 都有各自的优势,在适当的场景被广泛的部署和使用。本期讨论主要是希望通过对 Apache 和 Nginx 的一些重要实现细节和核心技术的讨论,深入的理解 Apache 和 Nginx 这两款著名开源软件各自的优势,以及在需要部署 HTTP 服务器,如何更好的做出选择。本次讨论不做 Apache 和 Nginx 孰优孰劣的笼统比较。
本期话题:
1、Apache 多进程模型的实现方法及其优势
2、Nginx事件驱动模型的实现方法及其优势
3、Apache 和 Nginx 对 HTTP 协议的处理细节(协议的解析等)
4、Apache 和 Nginx 各自使用的场景
1)静态压力测试,局域网单个大文件下载,apache只能到3m左右,nginx只能到4左右,使用native api的tomcat比apache稍低,而不使用native api或者说直接使用jsp的下载速度竟然是10M左右,这个情况至今不得其解。服务器是闲置服务器,没有其他业务跑。
2)首先,你要理解什么是代理服务器。 代理服务器通常是指代理内部网络对外部网络的出口访问服务器。客户机必须指定代理服务器,并通过代理服务器转发http请求来访问因特网。普通代理服务器也被设计为在Internet上搜寻多个不确定的服务器,而不是针对Internet上多个客户机的请求访问某一个固定的服务器,因此普通的Web代理服务器不支持外部对内部网络的访问请求。当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务。
3)Nginx用于在线视频点播支持服务很理想,原因有:
1>. 内置模块支持flv/mp4类型的在线http流式点播支持,而且配置简单
2>. 自编译可以在基本内置模块上进行少量改写以支持特殊特性,比如默认的点播标记是start,你可以依据客户端等自定义一个来做到一定的特性化,防止一般的盗链等。
4)apache的多进程模式在大并发情况下消耗的内存比较多。如果是纯的页面下载,感觉和nginx差别不大.如果是comet这样的长连接应用.存在很多不活动连接。nginx就优势很大了
5)nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能
6)nginx做为HTTP服务器,有以下几项基本特性:
处理静态文件,索引文件以及自动索引;打开文件描述符缓冲.
无缓存的反向代理加速,简单的负载均衡和容错.
FastCGI,简单的负载均衡和容错.不过现在和PHP,用fpm,很给力,动态调节
模块化的结构。包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter。
Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率 。牛逼就在于它的事件模型,epoll,可以轻松支持数万连接,当然服务器要适当的调优。nginx官方表示保持10,000个没有活动的连接,它只占2.5M内存,所以类似DOS这样的攻击对nginx来说基本上是毫无用处的。就稳定性而言,nginx比lighthttpd更胜一筹。Nginx采用了一些os提供的最新特性如对sendfile 的支持,从而大大提高了性能。貌似也要支持aio了,这估计应该也会显著提高nginx的效率
7)nginx在处理纯静态的文件(js,css,图片,html)的高并发上有优势,这方面nginx确实远优于apache.源于其处理机制不同。虽然有php-fpm的支持,但是处理动态php类的稳定性上目前还是apache要强于nginx.尺有所短,寸有所长,所以目前还是很多服务器在高可用的组合架构中,依然是2者都在使用!
8)
1>Apache 多进程模型的实现方法及其优势
Apache有两种工作模型,一种是基于进程的prefork模型,一种是基于线程和进程混合的Worker模型
1.1 prefork 控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,等待一秒钟,继续创建两 个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足MinSpareServers设置的值为止。这种模式 可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。MaxSpareServers设置了最大的空闲进程数,如果空闲进程数大于这个值,Apache会自动kill掉一些多余进程。
可根据服务器的负载来调整这个值。MaxClients是这些指令中最为重要的一个,设定的是 Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grep http|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。虽然理论上这个值越大,可以 处理的请求就越多,但Apache默认的限制不能大于256。
1.2 相对于prefork,worker全新的支持多线程和多进程混合模型的MPM。由于 使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是,worker也使用了多进程,每个进程又生成多个线程,以 获得基于进程服务器的稳定性。Worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的ThreadsPerChild线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients设置了同时连入的clients最大总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。
1.3 相对来说,prefork方式速度要稍高于worker,然而它需要的cpu和memory资源也稍多于woker。需要对网站进行行为分析。一般是分析日志。然后再根据实际情况做判断。
2>Nginx事件驱动模型的实现方法及其优势
2.1 克服了多线程模型的并发量缺点,对请求采用事件驱动方式处理,这里的事件通常是IO事件,其底层的实现依赖于非阻塞IO和IO多路复用。事件驱动模型很适合于IO密集型的应用,这种应用对CPU消耗代价甚至要小于线程间的切换代价,比如各种proxy。而现在的proxy,基本都标配Epoll,使得能支持的并发请求数在万级别。像lightty、nginx,是事件驱动模型的经典应用,请求的处理流程是由状态机驱动的,每次状态的切换经由一次事件触发,这样单线程就够用了(当然,如果需要支持更高的处理能力,可以采用多进程的事件驱动模型)。
2.2事件驱动的缺点在于:1)单个处理阶段不能阻塞太长,如果有这方面的问题,一般可采用专门的线程处理,处理完了再触发事件让主线程接着处理。2)整个事件驱动流程通常是固定的,在一个线程内由调度器完成,这使得它很难做的通用,使应用可以自定义流程。
3>Apache 和 Nginx 对 HTTP 协议的处理细节(协议的解析等)
HTTP协议过于庞大复杂,就以为例:
1---Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记 (Http Reponse Header)此文件在服务期端最后被修改的时间,格式类似这样:
Last-Modified: Mon, 22 Nov 2010 16:29:24 GMT客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头(Http Request Header),询问该时间之后文件是否有被修改过:
If-Modified-Since: Mon, 22 Nov 2010 16:29:24 GMT如果服务器端的资源没有变化,则自动返回 HTTP 304 (NotChanged.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类 似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
注:如果If-Modified-Since的时间比服务器当前时间(当前的请求时间request_time)还晚,会认为是个非法请求
2---Etag工作原理
HTTP 协议规格说明定义ETag为”被请求变量的实体标记” (参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:
Etag: "xok.la-961AA72-4CEA99B4415628″客户端的查询更新格式是这样的:
If-None-Match: "xok.la-961AA72-4CEA99B4415628″如果ETag没改变,则返回状态304。
即:在客户端发出请求 后,Http Reponse Header中包含 Etag: “xok.la-961AA72-4CEA99B4415628″
标识,等于告诉Client端,你拿到的这个的资源有表示 ID:xok.la-961AA72-4CEA99B4415628。当下次需要发Request索要同一个 URI的时候,浏览器同时发出一个If-None-Match报头( Http RequestHeader)此时包头中信息包含上次访问得到的Etag: “xok.la-961AA72-4CEA99B4415628″标识。
If-None-Match: "xok.la-961AA72-4CEA99B4415628",这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果 If- None-Match为False,不返回200,返回304 (Not Modified) Response。
3>Expires
给出的 日期/时间后,被响应认为是过时。如Expires: Thu, 02 Apr 2009 05:14:08 GMT 需和Last-Modified结合使用。用于控制请求文件的有效时间,当请求数据在有效期内时客 户端浏览器从缓存请求数据而不是服务器端. 当缓存中数据失效或过期,才决定从服务器更新数据。
4>Apache 和 Nginx 各自使用的场景
Apache 后台服务器(主要处理php及一些功能请求 如:中文url)
Nginx 前端服务器(利用它占用系统资源少得优势来处理静态页面大量请求)
总体来说,随着nginx功能得完善将使他成为今后web server得主流。
9)很久以前做过nginx模块开发,nginx把各个请求数包构建成一个链式结构,事件触发了就一个个处理,因此非常快。nginx模块开发非常方便,但是只有一个简单的例子,资料非常少
10)以前有做过一些基础测试,在2台硬件配置一样的linux系统上,分别装apache和nginx(php-fpm);
apache的服务器是:Apache/2.2.15 (CentOS),PHP/5.3.10
nginx的是:nginx/1.0.14、PHP/5.3.10.
配置文件除了运行必须修改的部分,其他都用默认的,没有做过修改,然后用webbench对nginx和apache的php和静态图片文件的处理能力做测试。同样的PHP代码,apache的执行处理能力要高于nginx(php-fpm),而处理存静态数据文件的情况下,nginx要明显优于apache.其他更细节的数据分析我没有继续深究!关于这个你可以找2台配置一样的旧电脑做个测试。多测试几次,然后取个平均值即可,稳定性方面需要在服务器上长期观测才好做分析判断。
先看静态图片处理能力,1000的并发就不发了,直接发10000的,apache的停止了响应,nginx依旧运行。
PHP的测试数据图,这里只发1000的,并发高了。2个服务器都会宕机。
1. 事件驱动就是来一个请求就处理一个,如果这个请求如select * from database花费10秒,则下一个请求什么都干不了。 而apache这样的面对10秒的select完全无压力,因为有许多的并发进程,可以干别的,如图像处理等,可以并发使用cpu资源,cpu资源足够多。
2.所以对于IO密集这样的任务,IO资源受限,只能一个人使用,所以事件驱动型服务器比较好。
而对于计算密集型,如php处理这样的,充分利用cpu的资源是重要的,要多进程apache服务器比较好。