一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的 。
而apache的常用工作方式(apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个进程在一个时刻只处理一个请求,因此,当并发数上到几千时,就同时有几千的进程在处理请求了 。这对操作系统来说,是个不小的挑战,进程带来的内存占用非常大,进程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的 。

文章插图
为什么nginx可以采用异步非阻塞的方式来处理呢,或者异步非阻塞到底是怎么回事呢?
我们先回到原点,看看一个请求的完整过程:首先,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据 。
具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧 。阻塞调用会进入内核等待,cpu就会让出去给别人用了,对单线程的worker来说,显然不合适,当网络事件越多时,大家都在等待呢,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了 。好吧,你说加进程数,这跟apache的线程模型有什么区别,注意,别增加无谓的上下文切换 。
所以,在nginx里面,最忌讳阻塞的系统调用了 。不要阻塞,那就非阻塞喽 。非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好呢,你慌什么,过会再来吧 。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没 。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的 。
nginx支持的事件模型如下:
Nginx支持如下处理连接的方法(I/O复用方法),这些方法可以通过use指令指定 。
select– 标准方法 。如果当前平台没有更有效的方法,它是编译时默认的方法 。你可以使用配置参数 –with-select_module 和 –without-select_module 来启用或禁用这个模块 。
poll– 标准方法 。如果当前平台没有更有效的方法,它是编译时默认的方法 。你可以使用配置参数 –with-poll_module 和 –without-poll_module 来启用或禁用这个模块 。
kqueue– 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 macOS X. 使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃 。
epoll – 高效的方法,使用于Linux内核2.6版本及以后的系统 。在某些发行版本中,如SuSE 8.2, 有让2.4版本的内核支持epoll的补丁 。
rtsig – 可执行的实时信号,使用于Linux内核版本2.2.19以后的系统 。默认情况下整个系统中不能出现大于1024个POSIX实时(排队)信号 。这种情况 对于高负载的服务器来说是低效的;所以有必要通过调节内核参数 /proc/sys/kernel/rtsig-max 来增加队列的大小 。
可是从Linux内核版本2.6.6-mm2开始,这个参数就不再使用了,并且对于每个进程有一个独立的信号队列,这个队列的大小可以用 RLIMIT_SIGPENDING 参数调节 。当这个队列过于拥塞,nginx就放弃它并且开始使用 poll 方法来处理连接直到恢复正常 。
/dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
eventport – 高效的方法,使用于 Solaris 10. 为了防止出现内核崩溃的问题,有必要安装这个 安全补丁 。
在linux下面,只有epoll是高效的方法
下面再来看看epoll到底是如何高效的
Epoll是Linux内核为处理大批量句柄而作了改进的poll 。要使用epoll只需要这三个系统调用:epoll_create(2),epoll_ctl(2),epoll_wait(2) 。它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44),在2.6内核中得到广泛应用 。
epoll的优点支持一个进程打开大数目的socket描述符(FD)
select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048 。对于那些需要支持的上万连接数目的IM服务器来说显 然太少了 。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案) 。
推荐阅读
- 5分钟学会从此不违章! 交通图解
- 离职要懂得维权!一文让你彻底搞懂经济补偿的N、N+1、2N、2N+1
- 2步搞定抖音怎么把抖音标志去掉,简简单单
- 苹果手机照片彻底删除后怎么恢复?照片误删这样恢复
- 三个步骤帮你轻松搞定微信公众号平台!
- 6分钟教你彻底理解三原色的色彩原理,轻松模仿各路大神作品色调
- 简单直接。一文搞懂医疗险
- 是玉帝的女儿还是妹妹?《西游记》可能搞错了 二郎神的母亲
- 彻底弄懂UTF-8、Unicode、宽字符、locale
- 一文搞懂什么是 C# 计时器!
