Reactor模式
Reactor 模式
前言
针对传统阻塞 I/O 服务模型的 2 个缺点:
- 当并发数很大,就会创建大量的线程,占用很大系统资源
- 连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在 Handler对象中的
read
操作,导致上面的处理线程资源浪费
Reactor 模式的解决方案:本质就是I/O多路复用
- 多个连接共用一个阻塞对象
ServiceHandler
,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。 - 当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
概述
Reactor 模式也叫 Dispatcher
模式,即 I/O 多路复用监听事件,收到事件后,根据事件类型分配(Dispatch)给某个线程。
核心组件:
Reactor(也就是那个ServiceHandler):
Reactor
在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理线程来对IO
事件做出反应。Handlers(处理线程EventHandler):
处理线程执行
I/O
事件要完成的实际事件。
分类:
- 单
Reactor
单线程 - 单
Reactor
多线程 - 主从
Reactor
多线程
单Reactor单线程
通过单一Reactor调用select来监听网络的连接请求,收到事件后通过 Dispatch
进行分发。
- 如果是建立连接请求事件,则由
Acceptor
通过Accept
处理连接请求,然后创建一个Handler
对象处理连接完成后的后续业务处理 - 如果不是建立连接事件,则
Reactor
会分发调用连接对应的Handler
来响应
结构图:
缺点:
性能问题,只有一个线程,无法完全发挥多核 CPU
的性能。Handler
在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈、甚至导致整个节点故障。
Netty对应的代码
1 | EventLoopGroup eventGroup = new NioEventLoopGroup(1); |
单 Reactor多线程
同样是通过单一Reactor调用select来监听网络的连接请求,收到事件后通过 Dispatch
进行分发。
- 如果是建立连接请求事件,则由
Acceptor
通过Accept
处理连接请求,然后创建一个Handler
对象处理连接完成后的后续业务处理。 - 如果不是连接请求,则由
Reactor
分发调用连接对应的handler
来处理,但是这里handler
只负责响应事件,不负责处理事件,而是交由Worker
线程来进行业务处理。
结构图:
缺点:
- 单一的
Reactor
承担了所有时间监听,性能瓶颈明显,多线程数据共享和访问比较复杂。
Netty对应的代码
1 | // 默认2倍核心数 |
主从 Reactor 多线程
优化了前两种方案的单一Reactor
性能瓶颈问题,这个方案让Reactor
以主从的多线程方式运行。
Reactor
主线程MainReactor
对象通过select
监听连接事件,收到事件后,通过Acceptor
处理连接事件。- 当
Acceptor
处理连接事件后,MainReactor
将连接分配给SubReactor
,SubReactor
再将对应事件交由handler
处理。 handler
再分发给后面的worker
线程处理。
结构图:
Netty对应的代码
1 | EventLoopGroup bossGroup = new NioEventLoopGroup(); |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 goMars的学习随记!
评论