Netty初步学习

学习目标:

Netty


学习内容:

参考博客:https://blog.csdn.net/qq_35190492/article/details/113174359

要提Netty首先就要提NIO,而要提NIO首先就要提BIO,指的分别是Block IO和Non-Block IO,也就是阻塞和非阻塞IO,大致意思如下图:
在这里插入图片描述
在这里插入图片描述

大致的对比如下图:
在这里插入图片描述
NIO的简单模型:
在这里插入图片描述
BIO的简单模型:
在这里插入图片描述
Netty 是一个 NIO 客户端服务器框架,可快速轻松地开发网络应用程序,例如协议服务器和客户端。它极大地简化和简化了网络编程,例如 TCP 和 UDP 套接字服务器。

它的一个简单执行流程为:
在这里插入图片描述
从上图中可以看到一些比较重要的参数有:

Channel

Channel是 Java NIO 的一个基本构造。可以看作是传入或传出数据的载体。因此,它可以被打开或关闭,连接或者断开连接。

EventLoop 与 EventLoopGroup

​ EventLoop 定义了Netty的核心抽象,用来处理连接的生命周期中所发生的事件,在内部,将会为每个Channel分配一个EventLoop。

​ EventLoopGroup 是一个 EventLoop 池,包含很多的 EventLoop。

​ Netty 为每个 Channel 分配了一个 EventLoop,用于处理用户连接请求、对用户请求的处理等所有事件。EventLoop 本身只是一个线程驱动,在其生命周期内只会绑定一个线程,让该线程处理一个 Channel 的所有 IO 事件。

​ 一个 Channel 一旦与一个 EventLoop 相绑定,那么在 Channel 的整个生命周期内是不能改变的。一个 EventLoop 可以与多个 Channel 绑定。即 Channel 与 EventLoop 的关系是 n:1,而 EventLoop 与线程的关系是 1:1。

ServerBootstrap 与 Bootstrap

​ BootstarpServerBootstrap 被称为引导类,指对应用程序进行配置,并使他运行起来的过程。Netty处理引导的方式是使你的应用程序和网络层相隔离。

​ Bootstrap 是客户端的引导类,Bootstrap 在调用 bind()(连接UDP)和 connect()(连接TCP)方法时,会新创建一个 Channel,仅创建一个单独的、没有父 Channel 的 Channel 来实现所有的网络交换。

​ ServerBootstrap 是服务端的引导类,ServerBootstarp 在调用 bind() 方法时会创建一个 ServerChannel 来接受来自客户端的连接,并且该 ServerChannel 管理了多个子 Channel 用于同客户端之间的通信。

ChannelHandler 与 ChannelPipeline

ChannelHandler 是对 Channel 中数据的处理器,这些处理器可以是系统本身定义好的编解码器,也可以是用户自定义的。这些处理器会被统一添加到一个 ChannelPipeline 的对象中,然后按照添加的顺序对 Channel 中的数据进行依次处理。

ChannelFuture

​ Netty 中所有的 I/O 操作都是异步的,即操作不会立即得到返回结果,所以 Netty 中定义了一个 ChannelFuture 对象作为这个异步操作的“代言人”,表示异步操作本身。如果想获取到该异步操作的返回值,可以通过该异步操作对象的addListener() 方法为该异步操作添加监 NIO 网络编程框架 Netty 听器,为其注册回调:当结果出来后马上调用执行。Netty 的异步编程模型都是建立在 Future 与回调概念之上的。

Netty的线程模型

参考:https://blog.csdn.net/shenchaohao12321/article/details/89713518

当我们讨论 Netty线程模型的时候,一般首先会想到的是经典的 Reactor线程模型,尽管不同的NIO框架对于 Reactor模式的实现存在差异,但本质上还是遵循了 Reactor的基础线程模型。

Reactor主要有三种循序渐进的线程模型:
1、Reactor单线程模型
在这里插入图片描述
Reactor单线程模型,是指所有的IO操作都在同一个NIO线程上面完成。NIO线程的职责如下。

作为NIO服务端,接收客户端的TCP连接;
作为NIO客户端,向服务端发起TCP连接;
读取通信对端的请求或者应答消息;
向通信对端发送消息请求或者应答消息。

由于 Reactor模式使用的是异步非阻塞IO,所有的IO操作都不会导致阻塞,理论上一个线程可以独立处理所有IO相关的操作。从架构层面看,一个NIO线程确实可以完成其承担的职责。例如,通过 Acceptor类接收客户端的TCP连接请求消息,当链路建立成功之后,通过 Dispatch将对应的 ByteBuffer派发到指定的 Handler上,进行消息解码。用户线程消息编码后通过NIO线程将消息发送给客户端。
在一些小容量应用场景下,可以使用单线程模型。但是这对于高负载、大并发的应用场景却不合适,主要原因如下。

一个NIO线程同时处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送。当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈;

可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。

2、Reactor多线程模型
在这里插入图片描述
Reactor多线程模型的特点如下:

有专门一个NIO线程— Acceptor线程用于监听服务端,接收客户端的TCP连接请求。另外的网络IO操作——读、写等由一个NIO线程池负责,线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送。

需要注意的是一个NIO线程可以同时处理N条链路,但是一个链路只对应一个NIO线程,防止发生并发操作问题。

在绝大多数场景下, Reactor多线程模型可以满足性能需求。但是,在个别特殊场景中,一个NIO线程负责监听和处理所有的客户端连接可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握手进行安全认证,但是认证本身非常损耗性能在这类场景下,单独一个 Acceptor线程可能会存在性能不足的问题,为了解决性能问题,产生了第三种 Reactor线程模型——主从 Reactor多线程模型。

3、主从 Reactor多线程模型
在这里插入图片描述
主从 Reactor线程模型的特点是:服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池。 Acceptor接收到客户端TCP连接请求并处理完成后(可能包含接入认证等),将新创建的 SocketChannel注册到IO线程池(sub reactor线程池)的某个IO线程上,由它负责 SocketChannel的读写和编解码工作。 Acceptor线程池仅仅用于客户端的登录、握手和安全认证,一旦链路建立成功,就将链路注册到后端 sub reactor线程池的IO线程上,由IO线程负责后续的O操作。

Netty的线程模型

Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty可以同时支持 Reactor单线程模型、多线程模型和主从 Reactor多线层模型。
在这里插入图片描述
在这里插入图片描述
服务端启动的时候,创建了两个 NioEventLoopGroup,它们实际是两个独立的 Reactor线程池。一个用于接收客户端的TCP连接,另一个用于处理IO相关的读写操作,或者执行系统Task、定时任务Task等。

Netty用于接收客户端请求的线程池职责如下。
(1)接收客户端TCP连接,初始化 Channel参数;
(2)将链路状态变更事件通知给 ChannelPipeline。

Netty处理IO操作的 Reactor线程池职责如下。
(1)异步读取通信对端的数据报,发送读事件到 ChannelPipeline;
(2)异步发送消息到通信对端,调用 ChannelPipeline的消息发送接口;
(3)执行系统调用Task;
(4)执行定时任务Task,例如链路空闲状态监测定时任务。

通过调整线程池的线程个数、是否共享线程池等方式,Netty的 Reactor线程模型可以在单线程、多线程和主从多线程间切换,这种灵活的配置方式可以最大程度地满足不同用户的个性化定制。

为了尽可能地提升性能, Netty在很多地方进行了无锁化的设计,例如在IO线程内部进行串行操作,避免多线程竞争导致的性能下降问题。表面上看,串行化设计似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列一多个工作线程的模型性能更优。
在这里插入图片描述
Netty的 NioEventLoop读取到消息之后,直接调用 ChannelPipeline的fireChannelRead(Object msg)。只要用户不主动切换线程,一直都是由 NioEventLoop调用用户的 Handler,期间不进行线程切换。这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。


学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值