一、什么是 Reactor

三种 IO 模式和对应的开发模式如下:

BIONIOAIOThread-Per-ConnectionReactorProactor

Reactor 是一种开发模式,核心流程为:

1、注册感兴趣的事件
2、扫描是否有感兴趣的事件发生
3、事件发生后做相应的处理

简言之,注册事件(register)、扫描事件(select)、分发事件(dispatch)、处理事件(handle)。

 我们发现 Reactor 整个模式从始至终都围绕着事件,下面表格对应了 Netty 中不同的 Channel 监听的事件。

client/serverSocketChannel/ServerSocketChannelOP_ACCEPTOP_CONNECTOP_READOP_WRITEclientSocketChannelYYYserverServerSocketChannelYserverSocketChannelYY

  • 对于面向客户端的 SocketChannel 会监听连接、读、写三种事件。
  • 对于面向服务端的 ServerSocketChannel 只监听接收新连接的事件,会调用 accept() 方法并创建对应的 SocketChannel 。
  • 对于面向服务端的 SocketChannel ,即上面说的创建的子 Channel ,会监听读、写事件。

上面这些事件注册完成后,会有一个多路复用器一直扫描,在监听到这些事件后,Netty 会作相应的处理。

二、Reactor 三种版本

在网络编程中,如果每个客户端都与服务器保持一个连接,对于服务器来说是一个很大的压力。比如 BIO ,也就是上面表格的单线程模式:

 

上面的三个客户端与服务端之间有三个链接,对于每个链接都有一个 Handler 处理相应的事件:读,解码,计算,编码,响应,也就是占用了三个线程。而其中的读和响应都是阻塞线程的,这时一个严重的问题就出现了,阻塞的连接越多,占用的线程越多。

这种方式,抽象成代码就是:

 

我们来看 Reactor 如何解决上述出现的问题。

1、Reactor 单线程模式

 

单线程比较简单,所有的工作都由一个线程来做,包括接收连接、注册事件、扫描、分发、处理等。虽然解决了阻塞问题,但是单线程效率不高,一旦这个线程挂掉,整个系统就 game over 了,这是不能忍受的。

2、Reactor 多线程模式

 

为了解决单线程的问题,我们引入了线程池。在这个模式中,把比较耗时的 decode、compute、encode 操作交给线程池来做。与单线程模式对比,效率明显提升。

3、主从 Reactor 多线程模式

 

在上一版本的基础上,使用主从模式,新增主 Reactor 单独处理接收连接,然后将建立的 SocketChannel 注册给指定的从 Reactor。

三、在 Netty 中使用 Reactor 模式

 

在不指定线程数时,会根据 CPU 的核数来计算最优线程数。第三种主从模式,bossGroup 负责接收连接并将 SocketChannel 注册到 workGroup 上,woekGroup 负责处理其他事件。

如果觉得本文对你有帮助,可以转发关注支持一下
原文链接:https://aysaml.com/articles/2020/10/23/1603444872972.html?utm_source=tuicool&utm_medium=referral