一、Reactor
Reactor 模式就是对 I/O 多路复⽤作了⼀层封装,让使⽤者不⽤考虑底层⽹络 API 的细节,只需要关注应⽤代码的编写。
I/O 多路复⽤监听事件,收到事件后,根据事件类型分配给某个进程 / 线程。
Reactor 模式主要由 Reactor 和处理资源池这两个核⼼部分组成,它俩负责的事情如下:
Reactor 负责监听和分发事件,事件类型包含连接事件、读写事件;
处理资源池负责处理事件,如 read -> 业务逻辑 -> send;
Reactor 模式是灵活多变的,可以应对不同的业务场景,灵活在于:
Reactor 的数量可以只有⼀个,也可以有多个;
处理资源池可以是单个进程 / 线程,也可以是多个进程 /线程;
单 Reactor 单进程
这种⽅案存在 2 个缺点:
第⼀个缺点,因为只有⼀个进程,⽆法充分利⽤ 多核 CPU 的性能;
第⼆个缺点,Handler 对象在业务处理时,整个进程是⽆法处理其他连接的事件的,如果业务处理耗时⽐较⻓,那么就造成响应的延迟;
所以,单 Reactor 单进程的⽅案不适⽤计算机密集型的场景,只适⽤于业务处理⾮常快速的场景。
Redis 采⽤的正是「单 Reactor 单进程」的⽅案,因为 Redis 业务处理主要是在内存中完成,性能瓶颈不在 CPU 上(不涉及CPU运算),所以 Redis 对于命令的处理是单进程的⽅案。
单 Reactor 多进程
单 Reator 多线程的⽅案优势在于能够充分利⽤多核 CPU 的性能,那既然引⼊多线程,那么⾃然就带来了多线程竞争资源的问题。
⽽多线程间可以共享数据,虽然要额外考虑并发问题,但是这远⽐进程间通信的复杂度低得多,因此实际应⽤中也看不到单 Reactor 多进程的模式。
另外,「单 Reactor」的模式还有个问题,因为⼀个 Reactor 对象承担所有事件的监听和响应,⽽且只在主线程中运⾏,在⾯对瞬间⾼并发的场景时,容易成为性能的瓶颈的地⽅。
要解决「单 Reactor」的问题,就是将「单 Reactor」实现成「多 Reactor」,这样就产⽣了多 Reactor 多进程 / 线程的⽅案。
多Reactor 多线程
⼤名鼎鼎的两个开源软件 Netty 和 Memcache 都采⽤了「多 Reactor 多线程」的⽅案。
多Reactor 多进程
采⽤了「多 Reactor 多进程」⽅案的开源软件是 Nginx
二、Proactor
Reactor 是⾮阻塞同步⽹络模式,感知的是就绪可读写事件。Proactor 是异步⽹络模式, 感知的是已完成的读写事件。
Reactor 模式是基于「待完成」的 I/O 事件,⽽ Proactor 模式则是基于「已完成」的 I/O 事件。
可惜的是,在 Linux 下的异步 I/O 是不完善的,aio 系列函数是由 POSIX 定义的异步操作接⼝,不是真正的操作系统级别⽀持的,⽽是在
⽤户空间模拟出来的异步,并且仅仅⽀持基于本地⽂件的 aio 异步操作,⽹络编程中的socket 是不⽀持的,这也使得基于 Linux 的⾼性能⽹络程序都是使⽤ Reactor ⽅案。
⽽ Windows ⾥实现了⼀套完整的⽀持 socket 的异步编程接⼝,这套接⼝就是 IOCP ,是由操作系统级别实现的异步 I/O,真正意义上异步 I/O,因此在 Windows ⾥实现⾼性能⽹络程序可以使⽤效率更⾼的 Proactor ⽅案。