天天看点

【netty系列】一文讲透传统IO模型与reactor模型

文章目录

    • 1、传统IO模型
    • 2、reactor模型
      • 2.1、单reactor单线程
      • 2.2、单reactor多线程
      • 2.3、主从reactor多线程
    • 总结

1、传统IO模型

【netty系列】一文讲透传统IO模型与reactor模型

传统IOjava代码传送门。

传统IO,称阻塞IO(BIO)。当客户端与服务端进行连接时,每一个客户端都会对应服务端一个单独的线程与其连接,这个thread完成对应的业务处理。当没有业务处理时,这个线程也会一直存在,一直等待客户端发送信息。

当客户端没有信息传输的时候,服务端会一直卡在

inputStream.read

因此,传统IO,弊端很明显,当大量客户端连接服务器,但是信息发送不频繁时,会造成大量线程的浪费。

2、reactor模型

当客户端没有信息传输时,无需所有的线程都在等待状态。因此reactor引入selector的概念,selector实质上是完成了一个转发的功能,所有的客户端与selector连接,如果有客户端发送信息时,转发给一个线程进行处理。因此reactor模型也称为分发者模式。

reactor是一个事件驱动模型,当selector收到对应事件后,可以按照对应的事件通知不同的handler进行处理。有连接事件,读事件,写事件等。

当客户端没有事件产生时,客户端只与selector连接。避免的线程的浪费。

2.1、单reactor单线程

【netty系列】一文讲透传统IO模型与reactor模型

代码传送门。

此思路比较简单,没有多线程之间的通讯,功能全在一个线程中执行。弊端也很明显,单个线程无法发挥发挥CPU的性能。在业务处理中,系统的性能很容易达到瓶颈。

因此,此客户端适应于客户端数量有限,而且handler处理速度非常快的场景。例如redis的在业务处理的世界复杂度O(1)的情况。

2.2、单reactor多线程

【netty系列】一文讲透传统IO模型与reactor模型

reactor对象通过selector监控客户端的请求事件,收到事件之后进行分发。根据不同的事件进行分发。accept复杂连接事件,send负责发送事件,read负责读事件,handler复杂业务处理。这个模型可以充分发挥多喝CPU的处理能力。但是selector在单线程中运行,也容易出现性能瓶颈。

2.3、主从reactor多线程

【netty系列】一文讲透传统IO模型与reactor模型
  1. Reactor主线程 MainReactor 对象通过select 监听连接事件, 收到事件后,通过Acceptor 处理连接事件
  2. 当 Acceptor 处理连接事件后,MainReactor 将连接分配给SubReactor
  3. subreactor 将连接加入到连接队列进行监听,并创建handler进行各种事件处理
  4. 当有新事件发生时, subreactor 就会调用对应的handler处理
  5. handler 通过read 读取数据,分发给后面的worker 线程处理
  6. worker 线程池分配独立的worker 线程进行业务处理,并返回结果
  7. handler 收到响应的结果后,再通过send 将结果返回给client
  8. Reactor 主线程可以对应多个Reactor 子线程, 即MainRecator 可以关联多个SubReactor

优缺点说明:

  • 优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
  • 优点:父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。
  • 缺点:编程复杂度较高

总结

如此看来reactor模型可以这样比喻:

单 Reactor 单线程,前台接待员和服务员是同一个人,全程为顾客服。

单 Reactor 多线程,1 个前台接待员,多个服务员,接待员只负责接待。

主从 Reactor 多线程,多个前台接待员,多个服务生。

reactor模型响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销扩展性好,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源复用性好,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。