专栏上一期我介绍了单服务器高性能的PPC和TPC模式,它们的优点是实现简单,缺点是都无法支撑高并发的场景,尤其是互联网发展到现在,各种海量用户业务的出现,PPC和TPC完全无能为力。今天我将介绍可以应对高并发场景的单服务器高性能架构模式:Reactor和Proactor。
Reactor
PPC模式最主要的问题就是每个连接都要创建进程(为了描述简洁,这里只以PPC和进程为例,实际上换成TPC和线程,原理是一样的),连接结束后进程就销毁了,这样做其实是很大的浪费。为了解决这个问题,一个自然而然的想法就是资源复用,即不再单独为每个连接创建进程,而是创建一个进程池,将连接分配给进程,一个进程可以处理多个连接的业务。
引入资源池的处理方式后,会引出一个新的问题:进程如何才能高效地处理多个连接的业务?当一个连接一个进程时,进程可以采用“read->业务处理->write”的处理流程,如果当前连接没有数据可以读,则进程就阻塞在read操作上。这种阻塞的方式在一个连接一个进程的场景下没有问题,但如果一个进程处理多个连接,进程阻塞在某个连接的read操作上,此时即使其他连接有数据可读,进程也无法去处理,很显然这样是无法做到高性能的。
解决这个问题的最简单的方式是将read操作改为非阻塞,然后进程不断地轮询多个连接。这种方式能够解决阻塞的问题,但解决的方式并不优雅。首先,轮询是要消耗CPU的;其次,如果一个进程处理几千上万的连接,则轮询的效率是很低的。
为了能够更好地解决上述问题,很容易可以想到,只有当连接上有数据的时候进程才去处理,这就是I/O多路复用技术的来源。
I/O多路复用技术归纳起来有两个关键实现点:
· 当多条连接共用一个阻塞对象后,进程只需要在一个阻塞对象上等待,而无须再轮询所有连接,常见的实现方式有select、epoll、kqueue等。
· 当某条连接有新的数据可以处理时,操作系统会通知进程,进程从阻塞状态返回,开始进行业务处理。
I/O多路复用结合线程池,完美地解决了PPC和TPC的问题,而且“大神们”给它取了一个很牛的名字:Reactor,中文是“反应堆”。联想到“核反应堆”,听起来就很吓人,实际上这里的“反应”不是聚变、裂变反应的意思,而是“事件反应”的意思,可以通俗地理解为“来了一个事件我就有相应的反应”,这里的“我”就是Reactor,具体的反应就是我们写的代码,Reactor会根据事件类型来调用相应的代码进行处理。Reactor模式也叫Dispatcher模式(在很多开源的系统里面会看到这个名称的类,其实就是实现Reactor模式的),更加贴近模式本身的含义,即I/O多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程。
Reactor模式的核心组成部分包括Reactor和处理资源池(进程池或线程池),其中<