Reactor线程模型


Reactor是什么?
The reactor design_pattern is an event_handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.
from wiki

通过wiki中的定义我们可以发现Reactor的重点

  1. 事件驱动
  2. 可以处理一个或多个输入源
  3. 通过多路复用将请求的事件分发给对应的处理器处理



根据大神Doug Lea 在 《Scalable IO in Java 》中的介绍,Reacotr模型主要分为三个角色

  1. Reactor:把IO事件分配给对应的handler处理
  2. Acceptor:处理客户端连接事件
  3. Handler:处理非阻塞的任务



为什么使用Reactor?



传统阻塞IO模型的不足

  1. 每个连接都需要独立线程处理,当并发数大时,创建线程数多,占用资源
  2. 采用阻塞IO模型,连接建立后,若当前线程没有数据可读,线程会阻塞在读操作上,造成资源浪费




针对传统阻塞IO模型的两个问题,可以采用如下的方案

  1. 基于池化思想,避免为每个连接创建线程,连接完成后将业务处理交给线程池处理
  2. 基于IO复用模型,多个连接共用同一个阻塞对象,不用等待所有的连接。遍历到有新数据可以处理时,操作系统会通知程序,线程跳出阻塞状态,进行业务逻辑处理


Reactor线程模型的思想就是基于IO复用和线程池的结合

Reactor线程模型分类
根据Reactor的数量和处理资源的线程数量的不同,分为三类:

  1. 单Reactor单线程模型
  2. 单Reactor多线程模型
  3. 多Reactor多线程模型



单Reactor单线程模型
这种模型在Reactor中处理事件,并分发事件,如果是连接事件交给acceptor处理,如果是读写事件和业务处理就交给handler处理,但始终只有一个线程执行所有的事情



该线程模型的不足

  1. 仅用一个线程处理请求,对于多核资源机器来说是有点浪费的
  2. 当处理读写任务的线程负载过高后,处理速度下降,事件会堆积,严重的会超时,可能导致客户端重新发送请求,性能越来越差
  3. 单线程也会有可靠性的问题



针对上面的种种不足,就有了下面的线程模型

单Reactor多线程模型
这种模型和第一种模型到的主要区别是把业务处理从之前的单一线程脱离出来,换成线程池处理,也就是Reactor线程只处理连接事件和读写事件,业务处理交给线程池处理,充分利用多核机器的资源、提高性能并且增加可靠性


该线程模型的不足

Reactor线程承担所有的事件,例如监听和响应,高并发场景下单线程存在性能问题

多Reactor多线程模型
这种模型下和第二种模型相比是把Reactor线程拆分了mainReactor和subReactor两个部分,mainReactor只处理连接事件,读写事件交给subReactor来处理。业务逻辑还是由线程池来处理


mainRactor只处理连接事件,用一个线程来处理就好。处理读写事件的subReactor个数一般和CPU数量相等,一个subReactor对应一个线程,业务逻辑由线程池处理

这种模型使各个模块职责单一,降低耦合度,性能和稳定性都有提高
这种模型在许多项目中广泛应用,比如Netty的主从线程模型等

Reactor三种模式形象比喻
餐厅一般有接待员和服务员,接待员负责在门口接待顾客,服务员负责全程服务顾客
Reactor的三种线程模型可以用接待员和服务员类比

    1. 单Reactor单线程模型:接待员和服务员是同一个人,一直为顾客服务。客流量较少适合
    2. 单Reactor多线程模型:一个接待员,多个服务员。客流量大,一个人忙不过来,由专门的接待员在门口接待顾客,然后安排好桌子后,由一个服务员一直服务,一般每个服务员负责一片中的几张桌子
    3. 多Reactor多线程模型:多个接待员,多个服务员。这种就是客流量太大了,一个接待员忙不过来了

转自:https://zhuanlan.zhihu.com/p/69341619