章节索引 :

Netty Reactor 模型之多线程模型

1. 前言

回顾上节,我们了解了什么是传统堵塞 I/O 模型,什么是单 Reactor 单线程模型,以及它们的缺点,本节内容主要是针对单 Reactor 单线程模型的缺点进行升级,让它的性能得到进一步的提高。

2. 如何进行优化

首先,我们思考一下单 Reactor 单线程的性能瓶颈在哪里?

主要有以下两个方面的性能上的缺点:

  1. 整个流程处理都是单线程,包括:监听客户端连接、分发客户端请求、处理客户端请求及响应,整个流程非常的复杂和耗时,只有一个线程的话,如果客户端数量比较多,那么将处理不过来;

  2. 客户端的监听、请求分发和业务处理耦合一起,业务处理将是一个未知的东西,如果这个业务很复杂需要连接数据库,并且操作好几张表,那么可能将会耗时相对的长,那么将会影响其他的客户端请求。

针对单 Reactor 单线程的两个缺点,本节我们主要针对第二个缺点来进行改造,其实一般提到线程模型的概念,一般都喜欢结合生活当中的饭店经营模式这个俗套来进行说明,可以加深同学们的印象。

  1. 单 Reactor 单线程模型: 好比一个小饭馆,老板既要招待客人又要炒菜,老板服务效率既然很低,挣的钱既然不会太多;

  2. 单 Reactor 多线程模型: 老板专门招待客人,并且把客人的点菜传达给后厨,后厨有多个厨师负责炒菜,这样的话,炒菜的速度既然提高,客人也会觉得满意;

  3. 主从多线程模式: 虽然有多个厨师负责炒菜,但是前台只要一个人在忙活,即使后厨炒菜速度很快,那么给客户上菜的效率也会受到影响,如果客户爆满的话,服务员只能累死的份了,那怎么办呢?增加服务员的人数不就解决问题了。

3. 单 Reactor 多线程模型

图片描述

架构图说明:

  1. Reactor 通过 Select 监听客户端请求事件,受到事件之后它本身不负责处理,而是把事件转发出去;

  2. 如果是建立连接请求,则由 Acceptor 进行处理;

  3. 如果不是建立连接请求,则转发给 Handler 负责处理;

  4. Handler 也不负责处理具体的业务,而是通过 read () 方法读取数据,然后再次分发给线程池去进行处理;

  5. 线程池会分配一个子线程去处理具体的业务,处理完成之后把结果返回给 Handler,并释放连接给连接池。

模式的优点:

  1. 可以充分的利用多核 CPU 的资源,提高处理任务的性能;

  2. 把业务处理从整个模型中剥离并丢给线程池去处理,避免某个业务处理或者某次业务处理太慢导致其他业务处理受到影响;

  3. 相比传统 I/O 堵塞模型,如果一旦没有客户端发起请求,那么线程池将不会处于堵塞状态,而是释放并且可以处理其他的业务,对于性能调优来说,最宝贵的就是线程资源,一旦线程资源得不到释放,整个应用将会卡掉。

模式的缺点:

  1. 多线程之间的数据共享和访问比较复杂,比如:Handler 给 Worker 线程分发数据;

  2. Reactor 处理所有事件的监听、转发、响应,都是单线程,在高并发的情况下,负责处理业务的 Worker 可能正常,但是 Reactor 就会容易遇到性能瓶颈;

  3. Reactor 如果一旦出现故障,那么整个通讯就会故障。

通过以上的分析,其实也是不推荐使用这种模式,除非客户端数量比较少,类似局域网内部的项目,但是我们还是需要了解整个模型是如何演变过来的,而不是一上来就讲解最好的那个方案。只有把整个演变过程了解了,我们才能更好的了解整个线程模型可能存在的性能瓶颈在哪里。

4. 小结

本节核心掌握的知识点

  1. 了解单 Reactor 单线程的弊端在哪里;

  2. 通过线程池的方式去解决单 Reactor 单线程存在的缺点;

  3. 通过饭馆经营的案例来讲解几种 Reactor 线程模型的概念,让大家更加容易理解;

  4. 介绍了什么是单 Reactor 多线程模型,以及它的优缺点是什么。