nginx如何处理⾼并发
⼀、阅前热⾝
为了更加形象的说明同步异步、阻塞⾮阻塞,我们以⼩明去买奶茶为例。
1、同步与异步
①同步与异步的理解
同步与异步的重点在消息通知的⽅式上,也就是调⽤结果通知的⽅式。
同步
当⼀个同步调⽤发出去后,调⽤者要⼀直等待调⽤结果的通知后,才能进⾏后续的执⾏
异步:
当⼀个异步调⽤发出去后,调⽤者不能⽴即得到调⽤结果的返回。
异步调⽤,要想获得结果,⼀般有两种⽅式:
1、主动轮询异步调⽤的结果;
2、被调⽤⽅通过callback来通知调⽤⽅调⽤结果。
②:⽣活实例
同步买奶茶:⼩明点单交钱,然后等着拿奶茶;
异步买奶茶:⼩明点单交钱,店员给⼩明⼀个⼩票,等⼩明奶茶做好了,再来取。
异步买奶茶,⼩明要想知道奶茶是否做好了,有两种⽅式:
1、⼩明主动去问店员,⼀会就去问⼀下:“奶茶做好了吗?”...直到奶茶做好。
2、等奶茶做好了,店员喊⼀声:“⼩明,奶茶好了!”,然后⼩明去取奶茶。
2、阻塞与⾮阻塞
①阻塞与⾮阻塞的理解
阻塞与⾮阻塞的重点在于进/线程等待消息时候的⾏为,也就是在等待消息的时候,当前进/线程是挂起状态,还是⾮挂起状态。
阻塞
阻塞调⽤在发出去后,在消息返回之前,当前进/线程会被挂起,直到有消息返回,当前进/线程才会被激活.
⾮阻塞
⾮阻塞调⽤在发出去后,不会阻塞当前进/线程,⽽会⽴即返回。
②:⽣活实例
阻塞买奶茶:⼩明点单交钱,⼲等着拿奶茶,什么事都不做;
⾮阻塞买奶茶:⼩明点单交钱,等着拿奶茶,等的过程中,时不时刷刷微博、朋友圈...
3、总结
通过上⾯的分析,我们可以得知:
同步与异步,重点在于消息通知的⽅式;阻塞与⾮阻塞,重点在于等消息时候的⾏为。
所以,就有了下⾯4种组合⽅式
同步阻塞:⼩明在柜台⼲等着拿奶茶;
同步⾮阻塞:⼩明在柜台边刷微博边等着拿奶茶;
异步阻塞:⼩明拿着⼩票啥都不⼲,⼀直等着店员通知他拿奶茶;
异步⾮阻塞:⼩明拿着⼩票,刷着微博,等着店员通知他拿奶茶。
⼆、Nginx如何处理⾼并发
1、Apache⾯对⾼并发,为什么很⽆⼒?
Apache处理⼀个请求是同步阻塞的模式。
每到达⼀个请求,Apache都会去fork⼀个⼦进程去处理这个请求,直到这个请求处理完毕。
⾯对低并发,这种模式没什么缺点,但是,⾯对⾼并发,就是这种模式的软肋了。
1个客户端占⽤1个进程,那么,进程数量有多少,并发处理能⼒就有多少,但操作系统可以创建的进程数量是有限的。
多进程就会有进程间的切换问题,⽽进程间的切换调度势必会造成CPU的额外消耗。当进程数量达到成千上万的时候,进程间的切换就占了CPU⼤部分的时间⽚,⽽真正进程的执⾏反⽽占了CPU的⼀⼩部分,这就得不偿失了。
下⾯,举例说明这2种场景是多进程模式的软肋:
及时消息通知程序
⽐如及时聊天程序,⼀台服务器可能要维持数⼗万的连接(典型的C10K问题),那么就要启动数⼗万的进程来维持。这显然不可能。
调⽤外部Http接⼝时
假设Apache启动100个进程来处理请求,每个请求消耗100ms,那么这100个进程能提供1000qps。
但是,在我们调⽤外部Http接⼝时,⽐如QQ登录、微博登录,耗时较长,假设⼀个请求消耗10s,也就是1个进程1s处理0.1个请求,那么100个进程只能达到10qps,这样的处理能⼒就未免太差了。
注:什么是C10K问题?
nginx和apache区别⽹络服务在处理数以万计的客户端连接时,往往出现效率低下甚⾄完全瘫痪,这被称为C10K问题。(concurrent 10000
connection)
综上,我们可以看出,Apache是同步阻塞的多进程模式,⾯对⾼并发等⼀些场景,是很苍⽩的。
2、Nginx何以问⿍⾼并发?
传统的服务器模型就是这样,因为其同步阻塞的多进程模型,⽆法⾯对⾼并发。
那么,有没有⼀种⽅式,可以让我们在⼀个进程处理所有的并发I/O呢?
答案是有的,这就是I/O复⽤技术。
①、I/O复⽤是神马?
最初级的I/O复⽤
所谓的I/O复⽤,就是多个I/O可以复⽤⼀个进程。
上⾯说的同步阻塞的多进程模型不适合处理⾼并发,那么,我们再来考虑⾮阻塞的⽅式。
采⽤⾮阻塞的模式,当⼀个连接过来时,我们不阻塞住,这样⼀个进程可以同时处理多个连接了。
⽐如⼀个进程接受了10000个连接,这个进程每次从头到尾的问⼀遍这10000个连接:“有I/O事件没?有的话就交给我处理,没有的话我⼀会再来问⼀遍。”
然后进程就⼀直从头到尾问这10000个连接,如果这1000个连接都没有I/O事件,就会造成CPU的空转,并且效率也很低,不好不好。
升级版的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流事件产⽣,然后进程就去处理这个进程。
如此,多⾼效!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论