nginx, swoole高并发原理初探

为了更加形象的说明同步异步,阻塞非阻塞,我们以去买奶茶为例。

同步与异步

同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。

同步:当一个同步调用发出去后,调用者要一直等待调用结果的通知,直到得到调用结果。

异步:当一个异步调用发出去后,调用者不能立即得到调用结果的返回。

异步调用,要想获得结果,一般有两种方式:

1,主动轮询异步调用的结果,

2,被调用方通过调来通知调用方调用结果。

同步买奶茶:点单交钱,然后等着拿奶茶;

异步买奶茶:点单交钱,店员给一个小票,等奶茶做好了,再来取。

异步买奶茶,小吴要想知道奶茶是否做好了,有两种方式:

1,主动去问店员,一会就去问一下:“奶茶做好了吗?”…直到奶茶做好。

2,等奶茶做好了,店员喊一声:“奶,茶好了!”,然后去取奶茶。

阻塞与非阻塞

阻塞与非阻塞的重点在于进/线程等待消息时候的行为,也就是在等待消息的时候,当前进/线程是挂起状态,还是非挂起状态。

1,阻塞调用发出去后,在消息返回之前,当前进/线程会被挂起,直到有消息返回,当前进/线程才会被激活。

2,非阻塞调用发出去后,不会阻塞当前进/线程,而会立即返回。

1,阻塞买奶茶:点单交钱,干等着拿奶茶,什么事都不做,

2,非阻塞买奶茶:点单交钱,等着拿奶茶,等的过程中,时不时刷刷微博,朋友圈……

Submit

同步与异步,重点在于消息通知的方式;

阻塞与非阻塞,重点在于等消息时候的行为。

所以,就有了下面4种组合方式

同步阻塞:在柜台干等着拿奶茶;

同步非阻塞:在柜台边刷微博边等着拿奶茶;

异步阻塞:拿着小票啥都不干,一直等着店员通知他拿奶茶;

异步非阻塞:拿着小票,刷着微博,等着店员通知他拿奶茶。

2Nginx如何处理高并发

Apache面对高并发,为什么很无力?

Apache处理一个请求是同步阻塞的模式。如图:

nginx、swoole高并发原理初探


每到达一个请求,Apache都会去fork一个子进程去处理这个请求,直到这个请求处理完毕。

面对低并发,这种模式没什么缺点,但是,面对高并发,就是这种模式的软肋了。

1个客户端占用1个进程,那么,进程数量有多少,并发处理能力就有多少,但操作系统可以创建的进程数量是有限的。

并且,多进程就会有进程间的切换问题,而进程间的切换调度势必会造成CPU的额外消耗。当进程数量达到成千上万的时候,进程间的切换就占了CPU大部分的时间片,而真正进程的执行反而占了CPU的一小部分,这就得不偿失了。

下面,举例说明这2种场景是多进程模式的软肋:

1、及时消息通知程序比如及时聊天程序,一台服务器可能要维持数十万的连接(典型的C10K问题),那么就要启动数十万的进程来维持。这显然不可能。

2、调用外部Http接口时假设Apache启动100个进程来处理请求,每个请求消耗100ms,那么这100个进程能提供1000qps。

但是,在我们调用外部Http接口时,比如QQ登录、微博登录,耗时较长,假设一个请求消耗10s,也就是1个进程1s处理0.1个请求,那么100个进程只能达到10qps,这样的处理能力就未免太差了。

注:什么是C10K问题?网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被称为C10K问题。(concurrent 10000 connection)

综上,我们可以看出,Apache是同步阻塞的多进程模式,面对高并发等一些场景,是很苍白的。

Nginx何以问鼎高并发

传统的服务器模型就是这样,因为其同步阻塞的多进程模型,无法面对高并发。

那么,有没有一种方式,可以让我们在一个进程处理所有的并发I/O呢?

答案是有的,这就是I/O复用技术。

所谓的I/O复用,就是多个I/O可以复用一个进程。

上面说的同步阻塞的多进程模型不适合处理高并发,那么,我们再来考虑非阻塞的方式。

采用非阻塞的模式,当一个连接过来时,我们不阻塞住,这样一个进程可以同时处理多个连接了。

比如一个进程接受了10000个连接,这个进程每次从头到尾的问一遍这10000个连接:“有I/O事件没?有的话就交给我处理,没有的话我一会再来问一遍。”

nginx, swoole高并发原理初探