知识卡片
多Reactor多进程/线程:职责分离反而让实现更简单
内容
针对[[单Reactor单进程与单Reactor多线程的取舍]]里”Reactor本身仍是单点瓶颈”这个问题,最直接的解法就是把单Reactor也拆成多个,形成多Reactor多进程/线程方案:父进程里的mainReactor只负责用select监听”连接建立”这一类事件,通过Acceptor接收新连接后,把这个连接分配给某个子进程;子进程里的subReactor把分到的连接加入自己的监听队列,并创建对应的Handler,之后这个连接上发生的所有事件(数据可读、可写等)都由这个子进程自己的subReactor监听、自己的Handler走完read→业务处理→send的完整流程。这个方案表面上看比单Reactor多线程更复杂(多了一层Reactor),但实际实现起来反而更简单,原因有三层:父进程和子进程的职责被切得非常干净——父进程只管接新连接,子进程只管把接到的连接的后续业务处理完,不存在职责重叠;父子进程之间的交互也很简单——父进程只需要把新连接”甩”给子进程,子进程不需要再把处理结果传回父进程(不像单Reactor多线程里子线程处理完还要把结果传回主线程的Handler);子进程之间彼此独立,网络模型这一层(select、read、send等)完全不需要任何同步共享机制(虽然”业务处理”这一层本身仍可能需要同步共享,但和网络模型这层完全脱钩)。目前著名的开源实现里,Nginx用的是多Reactor多进程,Memcache和Netty用的是多Reactor多线程;不过Nginx的实际实现和标准的多Reactor多进程方案有一个关键差异——它的主进程只负责创建监听端口,并不创建单独的mainReactor去accept连接,accept这个动作实际上是由各个子进程自己的Reactor来做的,通过锁机制保证同一时刻只有一个子进程在执行accept,accept到新连接后这个连接就直接归属这个子进程自己的Reactor处理,不会再被分配给别的子进程——这个设计进一步简化了父子进程之间原本还需要”分配连接”这一步的交互。
结构图:
flowchart TB
A["多Reactor多进程/线程"]
A --> B["mainReactor(父进程)<br/>只负责select监听连接建立事件+Acceptor接收"]
B --> C["把新连接分配给某个子进程"]
C --> D["subReactor(子进程)<br/>监听自己名下连接的后续所有事件"]
D --> E["Handler完成read→业务处理→send"]
A --> F["为何反而更简单:<br/>①父子职责清晰(父接连接/子处理业务)<br/>②交互简单(父只需甩连接,子无须回传结果)<br/>③子进程间网络模型层无须同步共享"]
A --> G["Nginx的差异化实现:<br/>父进程只开监听端口,不设mainReactor<br/>由子进程Reactor自己accept(加锁保证同时只1个accept)<br/>accept到的连接归属自己处理,不再分配"]