sheng的学习笔记-Reactor 模式

什么是 Reactor 模式

Reactor 模式一般翻译成反应器模式,也有人称为分发者模式。是基于事件驱动的设计模式,拥有一个或多个并发输入源,有一个服务处理器和多个请求处理器,服务处理器会同步的将输入的请求事件以多路复用的方式分发给相应的请求处理器。简单来说就是 由一个线程来接收所有的请求,然后派发这些请求到相关的工作线程中。

为什么使用 Reactor 模式

在 java 中,没有 NIO 出现之前都是使用 Socket 编程。Socket 的接收请求是阻塞的,需要处理完一个请求才能处理下一个请求,所以在面对高并发的服务请求时,性能就会很差。

那有人就会说使用多线程(如下图所示)。接收到一个请求,就创建一个线程处理,这样就不会阻塞了。实际上这样的确是可以在提升性能上起到一定的作用,但是当请求很多的时候,就会创建大量的线程,维护线程需要资源的消耗,线程之间的切换也需要消耗性能。而且系统创建线程的数量也是有限的,所以当高并发时,会直接把系统拖垮。

sheng的学习笔记-Reactor 模式_第1张图片

在 Reactor 模式中有三个重要的角色:

  • Reactor:负责响应事件,将事件分发到绑定了对应事件的 Handler,如果是连接事件,则分发到 Acceptor
  • Handler:事件处理器。负责执行对应事件对应的业务逻辑;
  • Acceptor:绑定了 connect 事件,当客户端发起 connect 请求时,Reactor 会将 accept 事件分发给 Acceptor 处理;

Reactor模式

单 Reactor 单线程版本

sheng的学习笔记-Reactor 模式_第2张图片

 

sheng的学习笔记-Reactor 模式_第3张图片

单Reactor单线程

只有一个 Selector 循环接受请求,客户端注册进来由 Reactor 接收注册事件,然后再由 Reactor 分发出去,由对应的 Handler 进行业务逻辑处理。

(1)Reactor 线程通过 select 监听事件,收到事件后通过 Dispatch 进行分发

(2)如果是连接建立事件,则将事件分发给 Acceptor,Acceptor 会通过 accept() 方法获取连接,并创建一个Handler 对象来处理后续的响应事件

(3)如果是IO读写事件,则 Reactor 会将该事件交由当前连接的 Handler 来处理

(4)Handler 会完成 read -> 业务处理 -> send 的完整业务流程
 

缺点

单线程的问题实际上是很明显的。只要其中一个 Handler 方法阻塞了,那就会导致所有的 client 的 Handler 都被阻塞了,也会导致注册事件也无法处理,无法接收新的请求。所以这种模式用的比较少,因为不能充分利用到多核的资源。因此,这种模式仅仅只能处理 Handler 比较快速完成的场景。

单 Reactor 多线程版本

sheng的学习笔记-Reactor 模式_第4张图片

 

sheng的学习笔记-Reactor 模式_第5张图片

(1)Reactor 线程通过 select 监听事件,收到事件后通过 Dispatch 进行分发

(2)如果是连接建立事件,则将事件分发给 Acceptor,Acceptor 会通过 accept() 方法获取连接,并创建一个Handler 对象来处理后续的响应事件

(3)如果是IO读写事件,则 Reactor 会将该事件交由当前连接对应的 Handler 来处理

(4)与单Reactor单线程不同的是,Handler 不再做具体业务处理,只负责接收和响应事件,通过 read 接收数据后,将数据发送给后面的 Worker 线程池进行业务处理。

(5)Worker 线程池再分配线程进行业务处理,完成后将响应结果发给 Handler 进行处理。

(6)Handler 收到响应结果后通过 send 将响应结果返回给 Client。

优缺点:

        相对于第一种模型来说,在处理业务逻辑,也就是获取到 IO读写事件之后,交由线程池来处理,Handler 收到响应后通过 send 将响应结果返回给客户端。这样可以降低 Reactor 的性能开销,从而更专注的做事件分发工作了,提升整个应用的吞吐,并且 Handler 使用了多线程模式,可以充分利用 CPU 的性能。但是这个模型存在的问题:

(1)Handler 使用多线程模式,自然带来了多线程竞争资源的开销,同时涉及共享数据的互斥和保护机制,实现比较复杂

(2)单个 Reactor 承担所有事件的监听、分发和响应,对于高并发场景,容易造成性能瓶颈。
 

多 Reactor 多线程版本

sheng的学习笔记-Reactor 模式_第6张图片

 

sheng的学习笔记-Reactor 模式_第7张图片

单Reactor多线程模型解决了 Handler 单线程的性能问题,但是 Reactor 还是单线程的,对于高并发场景还是会有性能瓶颈,所以需要将 Reactor 调整为多线程模式,也就是接下来要介绍的主从 Reactor 多线程模型。主从 Reactor 多线程模型将 Reactor 分成两部分:

(1)MainReactor:只负责处理连接建立事件,通过 select 监听 server socket,将建立的 socketChannel 指定注册给 subReactor,通常一个线程就可以了

(2)SubReactor:负责读写事件,维护自己的 selector,基于 MainReactor 注册的 SocketChannel 进行多路分离 IO 读写事件,读写网络数据,并将业务处理交由 worker 线程池来完成。SubReactor 的个数一般和 CPU 个数相同

流程:

(1)主线程中的 MainReactor 对象通过 select 监听事件,接收到事件后通过 Dispatch 进行分发,如果事件类型为连接建立事件则分发给 Acceptor 进行连接建立

(2)如果接收到的不是连接建立事件,则分发给 SubReactor,SubReactor 调用当前连接对应的 Handler 进行处理

(3)Handler 通过 read 读取数据后,将数据分发给 Worker 线程池进行业务处理,Worker 线程池则分配线程进行业务处理,完成后将响应结果发给 Handler

(4)Handler 收到响应结果后通过 send 将响应结果返回给 Client

优缺点:

        主从 Reactor 多线程模型的优点在于主线程和子线程分工明确,主线程只负责接收新连接,子线程负责完成后续的业务处理,同时主线程和子线程的交互也很简单,子线程接收主线程的连接后,只管业务处理即可,无须关注主线程,可以直接在子线程将处理结果发送给客户端。

        该 Reactor 模型适用于高并发场景,并且 Netty 网络通信框架也是采用这种实现
 

Reactor 优缺点:

(1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;

(2)可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销

(3)可扩展性,可以方便地通过增加 Reactor 实例个数来充分利用 CPU 资源;

(4)可复用性,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。
 

Java IO篇:什么是 Reactor 网络模型?_reactor模型_张维鹏的博客-CSDN博客

Reactor 高性能设计模式 - 知乎

设计模式 - Reactor 模式_reactor设计模式_yygr的博客-CSDN博客

你可能感兴趣的:(设计模式,java,开发语言,设计模式)