章节索引 :

Netty Reactor 模型之单线程模型

1. 前言

不同的线程模式,对于程序的性能差别是很大的,目前存在的线程模式主要有两种,分别是传统堵塞 I/O 服务模型Reactor 模型。其中又根据 Reactor 的数量和处理资源池线程的数量不同具体分为以下几种模型,具体如下:

  1. 单 Reactor 单线程;

  2. 单 Reactor 多线程;

  3. 主从 Reactor 多线程。

本节内容,主要讲解传统堵塞 I/O 模型单 Reactor 单线程模型的核心原理。

2. 学习目的

学习 Reactor 模型的好处在于可以知道传统的 I/O 的性能瓶颈在哪里,应该如何去提升性能。Reactor 模型只是纯理论上的东西,不涉及具体代码,并且它并不是只是针对 Netty 的一种理论,而是针对涉及 IO、涉及通信都需要去了解的理论方面的知识。包括常见知名的中间件 Redis、Nginx 等也都是基于这些线程模型去进行优化升级。

3. 传统堵塞 I/O 模型

3.1 模型介绍

图片描述

上图是传统堵塞模型的模型图,其特点如下所示:

  1. 每个客户端连接服务端时,服务端都会为客户端开辟一个线程专门处理其对应的业务请求;

  2. 每个线程独立完成其对应的客户端业务,读取数据、处理数据、响应数据,线程之间互不干扰;

  3. 如果某个客户端长时间没有请求数据时,那么服务端也不会释放线程,而是线程处于堵塞状态。

Socket 编程就是传统 I/O 堵塞模型,其缺点也非常的明显,具体如下:

  1. 如果客户端数量很大的情况,会为每个客户端都创建独立子线程,那么将消耗服务器大量的资源,增加 CPU 的工作压力,子线程虽然能提高处理速度,但是使用不合理反而降低服务器的性能;

  2. 如果某个客户端没有请求时,它还占用了服务器的资源,负责处理它业务的线程没有得到释放,而是一直堵塞于 read() 方法,直到下一次的请求进来。

3.2 模型优化

思考:针对传统的 I/O 模型的两个缺点,应该如何优化呢?

主要从两个方面进行改造,具体如下:

  1. I/O 多路复用: 它是操作系统级别的机制,大概原理是客户端连接时直接注册到操作系统的内核,当某个连接有新的数据可以处理时,操作系统通知应用程序,应用程序从堵塞状态切换到读取状态,开始进行业务处理。这种模型也叫反应器模型、分发者模式(Dispatcher)、通知这模式(notifier)。如果所有客户端都没有数据可处理时,应用程序只需要堵塞一个地方即可,相比传统 I/O 模型堵塞于各个线程的 read() 方法,这种模型的性能提高了很多;

  2. 线程池复用线程资源: 应用程序读取数据时,通过线程池创建子线程去处理业务、响应业务,处理完成之后自动释放线程,这样的好处在于 1)无需针对每个客户端独立创建子线程;2)子线程处理完成之后自动释放资源,而不是占着资源不释放,增加 CPU 的开销。

架构图如下所示:

图片描述

以上架构图分析:

  1. 多路复用器专门负责客户端请求的监听、读取数据、分发数据,但是不负责具体的业务处理;

  2. 业务处理是非常的复杂且耗时的,直接丢给线程池去负责处理;

  3. 整个架构的堵塞点在多路复用器,线程池则不会堵塞,如果没用客户端事件时,线程池可以释放去做别的事情;

  4. 通过以上的改造,那么整体的架构的性能就会得到不少提升。

4. 单 Reactor 单线程

单 Reactor 单线程模型,和上面的模型优化思路是类似的,具体如下:

图片描述

架构图说明

  1. Select 是 I/O 多路复用模型的标准网络编程 API,可以实现应用程序通过一个堵塞对象监听多路连接请求。Reactor 对象通过 Select 监听客户端请求事件,收到事件之后通过 Dispatch 进行分发;

  2. 如果事件类型是连接请求事件,则由 Acceptor 处理连接请求;

  3. 如果事件类型是普通业务(比如:客户端发送业务请求),则创建 Handler 来读取数据、业务处理、响应数据。

这种模式架构简单,但是存在以下缺点,具体如下:

  1. 如果客户端的连接数量很多的情况下,将无法支撑,因为负责处理客户端请求的 Reactor 只有一个;

  2. 负责处理业务的 Handler 只有一个,也就是说只有一个子线程负责处理具体业务,无法很好的利用多核 CPU 的性能;

  3. 如果线程出现问题,比如:意外终止、进入死循环,那么整个系统的通讯功能将会收到影响,造成通讯故障。

单 Reactor 单线程模型,一般适用于客户端数量比较少,业务处理复杂度很低,处理起来速度非常快的情况,因此真实业务场景不太建议使用。

5. 小结

本节主要掌握的知识点

  1. 常见的线程模型主要分为传统的 IO 模型和 Reactor 模型;

  2. Reactor 模型又细分单 Reactor 单线程模型、单 Reactor 多线程模型、主从多线程模型;

  3. 传统 IO 模型的缺点是什么,应该如何去优化;

  4. 单 Reactor 单线程的模型原理是什么,有什么优缺点。