转载:https://segmentfault.com/a/1190000007614502 《nginx、swoole高并发原理初探》
写的非常好,原理分析的简单通俗易懂。以下只是部分摘录。
(通过上面的分析,)我们可以得知:
同步与异步,重点在于消息通知的方式;
阻塞与非阻塞,重点在于等消息时候的行为。
所以,就有了下面4种组合方式
-
同步阻塞:小明在柜台干等着拿奶茶;
-
同步非阻塞:小明在柜台边刷微博边等着拿奶茶;
-
异步阻塞:小明拿着小票啥都不干,一直等着店员通知他拿奶茶;
-
异步非阻塞:小明拿着小票,刷着微博,等着店员通知他拿奶茶。
1、Apache面对高并发,为什么很无力?
Apache处理一个请求是同步阻塞的模式。
-
1个客户端占用1个进程,那么,进程数量有多少,并发处理能力就有多少,但操作系统可以创建的进程数量是有限的。
-
多进程就会有进程间的切换问题,而进程间的切换调度势必会造成CPU的额外消耗。当进程数量达到成千上万的时候,进程间的切换就占了CPU大部分的时间片,而真正进程的执行反而占了CPU的一小部分,这就得不偿失了。
Apache是同步阻塞的多进程模式,面对高并发等一些场景,是很苍白的。
2、Nginx何以问鼎高并发?
①、I/O复用是神马?
最初级的I/O复用
所谓的I/O复用,就是多个I/O可以复用一个进程。
采用非阻塞的模式,当一个连接过来时,我们不阻塞住,这样一个进程可以同时处理多个连接了。
升级版的I/O复用
上面虽然实现了基础版的I/O复用,但是效率太低了。于是伟大的程序猿们日思夜想的去解决这个问题...终于!
我们能不能引入一个代理,这个代理可以同时观察许多I/O流事件呢?
当没有I/O事件的时候,这个进程处于阻塞状态;当有I/O事件的时候,这个代理就去通知进程醒来?
于是,早期的程序猿们发明了两个代理---select、poll。
select、poll代理的原理是这样的:
当连接有I/O流事件产生的时候,就会去唤醒进程去处理。
但是进程并不知道是哪个连接产生的I/O流事件,于是进程就挨个去问:“请问是你有事要处理吗?”......问了99999遍,哦,原来是第100000个进程有事要处理。那么,前面这99999次就白问了,白白浪费宝贵的CPU时间片了!痛哉,惜哉...
注:select与poll原理是一样的,只不过select只能观察1024个连接,poll可以观察无限个连接。
上面看了,select、poll因为不知道哪个连接有I/O流事件要处理,性能也挺不好的。
那么,如果发明一个代理,每次能够知道哪个连接有了I/O流事件,不就可以避免无意义的空转了吗?
于是,超级无敌、闪闪发光的epoll被伟大的程序员发明出来了。
epoll代理的原理是这样的:
当连接有I/O流事件产生的时候,epoll就会去告诉进程哪个连接有I/O流事件产生,然后进程就去处理这个进程。
如此,多高效!
②、基于epoll的Nginx
有了epoll,理论上1个进程就可以无限数量的连接,而且无需轮询,真正解决了c10k的问题。
Nginx是基于epoll的,异步非阻塞的服务器程序。自然,Nginx能够轻松处理百万级的并发连接,也就无可厚非了。