Netty
1、概述
2、线程模型
3、核心组件
3.1 Channel
3.2 ChannelHandler和ChannelPipeline
3.3 EventLoop和EventLoopGroup
3.4 Future和Promise
4、创建过程
4.1 服务端创建过程
4.2 客户端创建过程
5、TCP粘包和拆包
6、序列化与反序列化
-
+
游客
注册
登录
线程模型
## 1 Reactor 线程模型 1. Reactor 模式是**基于事件驱动开发**的,核心组成部分包括**Reactor**和**线程池**,其中**Reactor 负责监听事件和分配事件**,**线程池负责处理事件**。 2. 根据**Reactor 的数量**和**线程池的数量**,又将 Reactor 分为三种模型: 1. **单 Reactor 单线程**。 2. **单 Reactor 多线程**。 3. **主从 Reactor 多线程**。 ### 1.1 单 Reactor 单线程 #### 1.1.1 原理 ![](/media/202201/2022-01-09_2202050.6954022419627751.png) 1. Reactor 内部**通过 Selector 监控连接事件**,**收到事件后通过 dispatch 进行分发**: 1. 如果是**连接建立的事件**,则**由 Acceptor 处理**,**通过 `accept` 建立连接**,**并创建一个 Handler 来处理连接后续的各种事件**。 2. 如果是**读写事件**,**直接调用连接对应的 Handler 来处理**。 2. Handler 主要**用来完成 $read \rightarrow (decode \rightarrow compute \rightarrow encode) \rightarrow send$ 的业务处理**。 #### 1.1.2 优缺点 ##### 1.1.2.1 优点 1. **模型简单**,**没有多线程**、**进程通信竞争问题**,**全部在一个线程完成**,主要适用于**客户端的数量有限**,**业务处理非常迅速的场景**,例如 Redis 在业务处理的时间复杂度为 $O(1)$ 的情况。 ##### 1.1.2.2 缺点 1. **性能问题**,**只有一个线程**,**无法完全发挥多核 CPU 的性能**。 2. **Handler 在处理某个连接上的业务时**,**整个进程无法处理其他连接事件**,**很容易导致性能瓶颈**。 3. **可靠性问题**,**线程意外终止**,**或者进入死循环**,**会导致整个系统通信模块不可用**,**不能接受和处理外部消息**,**造成节点故障**。 ### 1.2 单 Reactor 多线程 #### 1.2.1 原理 > 为了解决单 Reactor 单线程模型在高并发下的性能问题,就有了单 Reactor 多线程模型。 ![](/media/202201/2022-01-09_2202320.8026111727428262.png) 1. **主线程中**,Reactor 对象**通过 Selector 监控连接事件**,**收到事件后通过 dispatch 进行分发**: 1. 如果是**连接建立的事件**,则**由 Acceptor 处理**,**通过 `accept` 建立连接**,**并创建一个 Handler 来处理连接后续的各种事件**,而**Handler 只负责响应事件**,**不进行业务操作**,也就是**只进行 `read` 读取数据和 `write` 写出数据**,**业务处理交给一个线程池进行处理**。 2. **线程池分配一个线程完成真正的业务处理**,**然后将响应结果交给主进程的 Handler 处理**,**Handler 将结果 `send` 给客户端**。 #### 1.2.2 优缺点 ##### 1.2.2.1 优点 1. **可以充分利用多核 CPU 的处理能力**。 ##### 1.2.2.2 缺点 1. **多线程下会存在数据共享**、**并发安全问题**。 2. Reactor(这个 Reactor 是单线程的)**承担处理了所有的事件监听和响应**,**当我们的服务端遇到大量的客户端同时进行连接**,**或者在请求连接时执行一些耗时操作**,比如身份验证、权限检查等,**这种瞬时的高并发就容易成为性能瓶颈**。 ### 1.3 主从 Reactor 多线程 #### 1.3.1 原理 > 针对单 Reactor 多线程模型中,Reactor 在单线程下运行,高并发场景下容易造成性能瓶颈,可以让 Reactor 在多线程中运行得到下面的主从 Reactor 多线程模型。 ![](/media/202201/2022-01-09_2203070.5107936014146105.png) 1. **存在多个 Reactor**,**每个 Reactor 都有自己的 Selector 选择器**、**线程和 dispatch**,**Reactor 主线程可以对应多个 Reactor 子线程**,即**MainReactor 可以关联多个 SubReactor**。 2. Reactor**主线程 MainReactor 对象通过 Selector 监听连接事件**,**收到事件后**,**通过 Acceptor 处理连接事件**,**当 Acceptor 处理连接事件后**,**MainReactor 将连接分配给 SubReactor**。 3. **SubReactor 将 MainReactor 分配的连接加入连接队列中**,**然后通过自己的 Selector 进行监听**,**并创建一个 Handler 用于处理后续事件**。 4. **Handler 完成 $read \rightarrow 业务处理 \rightarrow send$ 的完整业务流程**。 #### 1.3.2 优缺点 ##### 1.3.2.1 优点 1. **父线程与子线程的数据交互简单**,**职责明确**,**父线程只需要建立新连接**,**子线程完成后续的业务处理**。 2. **父线程与子线程的数据交互简单**,**Reactor 主线程只需把新连接传给子线程**,**子线程无需返回数据**。 3. 这种模型在许多项目中广泛使用,例如 Ngnix 主从 Ngnix 多线程,Memcached 主从多线程,Netty 主从多线程。 ##### 1.3.2.2 缺点 1. **编程复杂**。 ### 1.4 总结 1. Reactor 模式可以按照如下方式来理解: 1. **单 Reactor 单线程**:**前台接待员和服务员是同一个**,**全程为顾客服务**。 2. **单 Reactor 多线程**:**1 个前台接待员**,**多个服务员**,**接待员只负责接待**。 3. **主从 Reactor 多线程**:**多个前台接待员**,**多个服务员**。 2. Reactor 模式具有以下优点: 1. **响应快**,**不必为单个同步事件阻塞**,虽然 Reactor 本身依然是同步的。 2. **可以最大程度的避免复杂的多线程及同步问题**,并且**避免了多线程切换的开销**。 3. **拓展性好**,**可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源**。 4. **复用性好**,**Reactor 模型本身与具体事件处理逻辑无关**,**具有很高的复用性**。 ## 2 Netty 的线程模型 > Netty 的线程模型并不是一成不变的,他实际取决于用户的启动参数配置,通过设置不同的启动参数,Netty 可以同时支持单 Reactor 单线程模型、单 Reactor 多线程模型、主从 Reactor 多线程模型。 ### 2.1 通俗模型 ![netty-1.png](/media/202108/2021-08-24_0954110.4100610178097567.png) ![netty-2.png](/media/202108/2021-08-24_0954190.8048430646789609.png) ### 2.2 详细模型 ![Netty-model.png](/media/202108/2021-08-24_0954350.5052641593023719.png) 1. **服务端启动的时候**,**创建了两个 NioEventLoopGroup**,他们实际上**是两个独立的 Reactor 线程池**,分别称为**BossGroup**和**WorkerGroup**,其中**BossGroup 主要负责接收客户端的 TCP 连接**,**WorkerGroup 主要负责处理 IO 相关的读写操作**。 > 1. NioEventLoopGroup 相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环都是一个 NioEventLoop。 > 2. NioEventLoop 表示一个不断循环的执行处理任务的线程,每个 NioEventLoop 都有一个 Selector,用于监听绑定在其上的 Socket 网络通信。 2. 每个 BossGroup 下面的 NioEventLoop 执行的步骤有以下三步: 1. **轮询 `accept` 事件**。 2. **处理 `accept` 事件**,**与客户端建立连接**,**生成一个 NioSocketChannel**,**并将其注册到某个 WorkerGroup 的 NioEventLoop 中的 Selector 上**。 3. **处理任务队列中的任务**。 3. 每个 WorkerGroup 下面的 NioEventLoop 执行的步骤有以下三步: 1. **轮询 `read` 或 `write` 事件**。 2. **处理 IO 事件**,即 `read` 或 `write` 事件,在**处理业务时**,**会使用 Pipeline**,他**包含了 NioSocketChannel**,即**通过 Pipeline 可以获得对应的 NioSocketChannel**,并且**Channel 中维护了很多的 Handler**,可以**用于业务的处理**。 3. **处理任务队列中的任务**。 ## 参考文献 1. [Netty 系列文章之 Netty 线程模型](https://juejin.cn/post/6844903974298976270)。 2. [Netty 网络模型](https://xuzhijie.top/index.php/%E7%BD%91%E7%BB%9C%E4%B8%8EIO/386.html)。 3. [《Netty 权威指南 第 2 版》]()
ricear
2022年1月9日 22:03
©
BY-NC-ND(4.0)
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码