← 返回题目列表

Reactor 模型是什么?有哪几种?

高频 中等 第 13 / 27 题 更新于 2026/07/28
Reactor事件驱动网络编程Netty

简化版

Reactor 是一种事件驱动的高并发网络编程模型:用 IO 多路复用(epoll) 监听所有连接上的事件(可读、可写、新连接),有事件到来就分发(dispatch)给对应的处理器(Handler) 去处理。核心是「一个(或几个)线程用 epoll 监听海量连接,只处理有事件的那些」,避免了「一连接一线程」的开销。按线程划分有三种:单 Reactor 单线程、单 Reactor 多线程、主从 Reactor 多线程(Netty 默认用主从多 Reactor)。

详细版

Reactor 的三个核心组件

  • Reactor(反应器/分发器):用 epoll 监听事件,事件来了负责分发给对应的 Acceptor 或 Handler;
  • Acceptor(接受器):专门处理「新连接建立」事件(accept 新连接);
  • Handler(处理器):处理已建立连接上的「读写」事件和业务逻辑。

三种 Reactor 结构

  • 单 Reactor 单线程:一个线程用 epoll 监听所有事件,accept 新连接、读写数据、处理业务全在这一个线程。简单,但业务处理阻塞会拖垮整个服务。**Redis(早期)**是典型。
  • 单 Reactor 多线程:一个 Reactor 线程负责 epoll 监听和 IO 读写,但把耗时的业务处理丢给一个线程池。IO 和业务分离,业务不再阻塞 IO 线程。
  • 主从 Reactor 多线程主 Reactor(mainReactor)专门 accept 新连接,接受后把连接分给从 Reactor(subReactor,通常多个) 去负责该连接的 IO 读写,业务再丢给 worker 线程池。分工最细、并发能力最强,Netty 默认就是这种。

完整版教学

一、Reactor 要解决什么:告别「一连接一线程」

传统的网络服务器用「一连接一线程/进程」——每来一个连接就开一个线程阻塞地处理它。这在连接少时简单直接,但连接一多(上万)就崩了:线程内存(每个约 1MB 栈)、上下文切换开销爆炸(这正是 C10K 问题,详见那道题)。

Reactor 的思路是反过来:不为每个连接配一个线程,而是用少量线程 + IO 多路复用——一个线程用 epoll 同时盯着成千上万个连接,只有哪个连接来了事件(有数据可读、可写、新连接),才去处理哪个。空闲的连接不占线程。这样少数几个线程就能撑起海量连接,这是所有高性能网络框架(Nginx、Redis、Netty)的共同基石。

「Reactor」这个名字的含义就是:它像一个「反应器」,静静地等待事件,事件一来就「反应」——分发给对应的处理器。 这是典型的事件驱动编程。

二、事件分发:Reactor 的核心机制

Reactor 的运转围绕「监听事件 → 分发事件」这个循环:

  1. Reactor 用 epoll 监听所有注册的 fd(监听 socket + 各连接 socket);
  2. epoll_wait 返回一批就绪事件
  3. Reactor 判断每个事件的类型并分发
    • 监听 socket 就绪(有新连接)→ 交给 Acceptor,accept 建立新连接,并把新连接注册到 epoll;
    • 连接 socket 就绪(有数据可读/可写)→ 交给对应的 Handler,读数据、处理业务、写响应。

这个「事件循环 + 分发」就是 Reactor 的灵魂。它把「什么时候有事」交给 epoll,把「有事了怎么处理」交给 Handler,Reactor 自己只管「牵线搭桥」。

三、单 Reactor 单线程:简单但有短板

最基础的形态——一个线程包揽一切:epoll 监听、accept、读写、业务处理全在这一个线程里。

  • 优点:模型极简,没有多线程的锁和竞争问题;
  • 致命短板:只要某个业务处理耗时(如一个复杂计算、一次慢查询),这一个线程就被占住,期间所有其他连接的事件都处理不了,整个服务卡住。

所以它只适合「业务处理极快」的场景。Redis 早期用单 Reactor 单线程正是因为 Redis 命令都是纯内存操作、极快,不会长时间占用线程(Redis 6 后网络 IO 部分才引入多线程)。

四、单 Reactor 多线程:IO 与业务分离

针对单线程「业务阻塞拖垮 IO」的问题,改进是把业务处理搬到线程池

  • Reactor 线程:仍负责 epoll 监听、accept、以及连接的读写 IO
  • worker 线程池:Handler 读到数据后,把耗时的业务处理丢给线程池,处理完再由 IO 线程写回。

这样 IO 线程不再被业务阻塞,能持续处理事件。但单个 Reactor 线程要处理所有连接的 IO 读写,在超高并发下这一个线程可能成为瓶颈——于是有了主从 Reactor。

五、主从 Reactor 多线程:Netty 的选择

这是并发能力最强的形态,把「接受连接」和「处理连接 IO」也分开:

  • 主 Reactor(mainReactor)只负责 accept 新连接。新连接建立后,把它「分派」给某个从 Reactor;
  • 从 Reactor(subReactor,一组):每个从 Reactor 负责一批连接的 IO 读写(各自有独立的 epoll);
  • worker 线程池:业务处理再丢给它。

分工:主 Reactor 管「进门」,从 Reactor 们管「和各自的客人读写」,worker 池管「干业务活」。三层分离,把连接接受、IO 读写、业务处理的压力分摊到不同线程,充分利用多核。

Netty 的默认模型就是主从 Reactor 多线程——bossGroup(主 Reactor,接受连接)+ workerGroup(从 Reactor,处理 IO),这也是它高性能的关键。

六、常见误区与追问

考点正确口径
事件分离器select/epoll 等等待就绪事件
事件处理器accept、read、write、业务处理回调
线程模型单 Reactor、主从 Reactor、多 worker
loop:
  events = selector.wait()
  for event in events:
    if accept: create connection
    if read: decode request
    if write: flush response

Reactor 的核心是把“等 IO”集中到事件循环,把“处理事件”分发给对应 handler。

  • 误区:Reactor 就是一个线程。 Reactor 是模式,既可以单线程,也可以主从 Reactor 加 worker 线程池。
  • 误区:所有业务都应放在事件循环里执行。 耗时业务会阻塞事件循环,应交给 worker 或异步后端处理。
  • 误区:Reactor 只适合网络服务器。 只要是事件驱动 IO,文件、定时器、信号等也可纳入类似事件循环。
  • 追问:单 Reactor 单线程有什么问题? 实现简单,但 CPU 密集任务和慢业务会拖住所有连接。
  • 追问:主从 Reactor 解决什么? 主 Reactor 负责 accept,从 Reactor 负责连接读写,分散事件循环压力。
  • 追问:Netty 为什么是典型 Reactor? EventLoop 监听 channel 事件,并把事件分发到 ChannelPipeline 中的 handler。

七、加强记忆

Reactor 是事件驱动的高并发模型:用 IO 多路复用(epoll)监听海量连接的事件,就绪了就分发给 Acceptor(接新连接)或 Handler(读写 + 业务),用少量线程撑海量连接,告别「一连接一线程」。三种:单 Reactor 单线程(简单、业务阻塞会拖垮,Redis 早期)、单 Reactor 多线程(业务丢线程池、IO 与业务分离)、主从 Reactor 多线程(主 accept + 从 IO + worker 业务,Netty 默认,并发最强)。