今天转载了一篇文章,对如上标题分析的很到位(很容易理解)
这个观点,阿铭不是绝对地赞同。原因如下:
1 如果网站为php站点,抛除静态的页面、图片之类的请求,单纯说php脚本这种请求,无论是apache还是nginx,性能旗鼓相当。因为,这种动态的请求,瓶颈不在web server本身上,而是在php连接的后端MySQL上,MySQL查询有性能问题,nginx跑再快也是没有任何意义的。就好比一台服务器cpu配置很高,但是磁盘比较差,那这个牛逼的cpu就没有啥意义了。
2 apache在最新版的2.4默认使用了event mpm的模式,这种模式其实也是基于epoll的,nginx之所以被认为快,就是因为使用了epoll模式。那如果两个web server都是epoll了,nginx也就没有啥优势了。更何况,apache的event还是进程+线程呢,多线程处理效率可是比nginx的多进程要高。
说完我的观点后,我们再来分析一下为什么大家都说apache性能没有nginx高,首先这个结论的前提是,两者要处理的请求为静态请求,动态的咱们不管,还有一点前提是apache基于select模式,而nginx基于epoll模式。
至于什么是select和epoll模式,这涉及到一个概念–网络I/O多路复用技术,这里给大家提供一篇文章做一个初步理解吧(http://blog.163.com/hbu_lijian/blog/static/126129153201261051637891/)。下面我们分别分析select模式和epoll模式的原理。
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。
epoll是在2.6内核中提出的,是之前的select和poll的增强版本。先说poll,poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。poll和select不同的是,它没有最大连接数限制。原因是它是基于链表来存储的。
相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。
我们用一个表来总结select、poll以及epoll的差异:
那么重点来了,如果还是不懂,继续看下面的白话文!
读完上述标书后,可能你对select和epoll还不是特别懂,那我们借用网上常见的一个例子来表达他们的差异吧。
假设你在大学中读书,要等待一个朋友来访,而这个朋友只知道你在A号楼,但是不知道你具体住在哪里,于是你们约好了在A号楼门口见面。
如果你使用的阻塞IO模型来处理这个问题,那么你就只能一直守候在A号楼门口等待朋友的到来,在这段时间里你不能做别的事情,不难知道这种方式的效率是低下的。
现在时代变化了,开始使用多路复用IO模型来处理这个问题,你告诉你的朋友来了A号楼找楼管大爷,让他帮你的朋友找到你。这里的楼管大爷扮演的就是多路复用IO的角色。
select版大爷做的是如下的事情:比如你的朋友来了,select版大爷比较笨,他带着你朋友挨个房间找你。
epoll版大爷就比较先进了,他早先记下了你的房间号,那么等你的朋友到来时,只需要告诉你朋友你在哪个房间即可。不再自己亲自带着你朋友满大楼的找人了。