Netty整体架构解析
一、整理架构
下图是Netty官网上给出的整体功能模块:

1. Core 核心层
Core核心层是Netty最精华的部分了,它提供了底层网络通信的抽象和实现,包括可扩展的事件模式、通用的通信API和支持零拷贝的ByteBuf
2. Protocol Support 协议支持层
协议支持层上基本覆盖了现在主流协议的编解码实现,例如HTTP、WebSocket、SSL、Protobuf、压缩、大文件传输等主流协议,此外Netty还支持自定义应用层协议。Netty丰富的协议支持降低了使用的开发成本,基于Netty可以快速开始HTTP、WebSocket等服务。
3. Transport Service 传输服务层
传输服务层提供了网络传输能力的定义和实现方法。它支持Socket、HTTP隧道和虚拟机通道等传输方式。Netty对TCP、UDP等数据阐述做了抽象和封装,开发者可以聚焦在业务逻辑的实现上,而不必关心底层数据传输的细节。
Netty的模块化设计具有较高的通用性和可扩展性,Netty不仅是一个有效的网络框架,还可以作为网络编程的工具箱。
二、Netty 的逻辑架构
Netty 的逻辑处理架构是典型的网络分层架构设计的,分别为网络通信层、事件调度层和服务编排层。每一层各司其职,如下图所示:

1. 网络通信层
网络通信层的职责就是执行网络I/O的操作。它支持多种网络协议和I/O模型的连接操作。当网络数据读取到内核缓冲区后,会触发各种网络事件,这些网络事件会分发给事件调度层来处理。网络通信层有三个核心组件:Bootstrap、ServerBootstrap和Channel。

- Bootstrap 和 ServerBootstrap
Bootstrap和ServerBootstrap都继承于AbstractBootstrap,在功能上很相似。Bootstrap是用于连接服务端的,一般用于Client的开发上;ServerBootstrap则是用于服务端启动绑定本地端口,一般绑定两个EventLoopGroup(主从多线程Reactor),一个称为boss,另外一个成为worker。
Bootstrap/ServerBootstrap组件更加方便我们配置和启动Netty程序,它是整个Netty程序的入口,串联了Netty所有核心组件的初始化工作。
- Channel
我们平常用到基本的 I/O 操作(bind()、connect()、read()和 write()),其本质都依赖于底层网络传输所提供的原语,在Java中就是Socket类。
Netty 的 Channel 接 口所提供的 API,大大地降低了直接使用Socket 类的复杂性。另外Channel 提供异步的网络 I/O 操作(如建立连接,读写,绑定端口),异步调用意味着任何 I/O 调用都将立即返回,并且不保证在调用结束时所请求的 I/O 操作已完成。
在调用结束后立即返回一个 ChannelFuture 实例,通过注册监听器到 ChannelFuture 上,支持 在I/O 操作成功、失败或取消时立马回调通知调用方。
此外,Channel 也是拥有许多预定义的、专门化实现的广泛类层次结构的根,比如:
- LocalServerChannel:用于本地传输的ServerChannel ,允许 VM 通信。
- EmbeddedChannel:以嵌入式方式使用的 Channel 实现的基类。
- NioSocketChannel:异步的客户端 TCP 、Socket 连接。
- NioServerSocketChannel:异步的服务器
- NioDatagramChannel: 异步的 UDP 连接。
- NioSctpChannel:异步的客户端 Sctp 连接,它使用非阻塞模式并允许将SctpMessage读/写到底层SctpChannel。
- NioSctpServerChannel:异步的 Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件 IO。
Channel事件状态:
出站事件

进站事件

2. 事件调度层
事件调度层通过Reactor线程模型对各类事件进行聚合处理,通过Selector主循环线程集成多种事件(I/O事件、信号事件、定时事件等),实际的业务处理逻辑交给服务编排层的ChannelHandler来处理。
事件调度层最核心的组件就是EventLoop和EventLoopGroup:EventLoopGroup实质上是Netty基于JDK线程池的抽象,本质就是线程池,主要负责接收I/O请求,并分配线程执行处理。而EventLoop可以理解成一个线程,EventLoop创建出来之后会跟一个线程绑定并且处理Channel中的事件。如下图所示:

1、一个EventLoopGroup包含一个或者多个EventLoop。EventLoop用于处理Channel生命周期的所有I/O事件。
2、EventLoop在同一时间只会跟一个线程绑定。每个EventLoop负责处理多个Channel。
3、每个新建的Channel,EventLoopGroup会选择一个EventLoop与其绑定。该Channel在生命周期内都可以对EventLoop及进行多次绑定和解绑。
Netty中不同的I/O模型有对应的EventLoop实现,下面是常用NioEventLoop的家族图谱:

EventLoopGroup是Netty Reactor线程模型的具体实现方式,Netty通过创建不同的EventLoopGroup参数配置就可以支持Reactor的三种线程模型:
- Reactor单线程模型:EventLoopGroup 只包含一个 EventLoop,Boss 和 Worker 使用同一个EventLoopGroup
- 非主从Reactor多线程模型:EventLoopGroup 包含多个 EventLoop,Boss 和 Worker 使用同一个EventLoopGroup
- 主从Reactor多线程模型:EventLoopGroup 包含多个 EventLoop,Boss 是主 Reactor,Worker 是从 Reactor,它们分别使用不同的 EventLoopGroup,主 Reactor 负责新的网络连接 Channel 创建,然后把 Channel 注册到从 Reactor

3. 服务编排层
服务编排的职责是组装各类服务,它是Netty的核心处理链,用以实现网络事件的动态编排和有序传播。
服务编排的核心组件有:ChannelPipeline、ChannelHandler、ChannelHandlerContext。
1、ChannelPipeline
Netty的核心编排组件,负责组装各类的ChannelHandler,实际数据的编解码以及加工处理的操作是由ChannelHandler来完成的。ChannelPipeline内部通过双向链表将不同的ChannelHandler链接在一起。当I/O读写事件触发时,ChannelPipeline会一次调用ChannelHandler列表对Channel的数据进行拦截和处理。
ChannelPipeline是线程安全的,因为每一个新的Channel都会对应一个新的ChannelPipeline。一个ChannelPipeline关联一个EventLoop,一个EventLoop只会绑定一个线程。如下如图截取来自ChannelPipeline类注释中:
可以看得出来,ChannelPipeline中包含入站ChannelInboundHandler和出战的ChannelOutboundHandler两种处理器,结合服务端和客户端的数据收发来看,如下图:

客户端和服务端都有自己的ChannelPipeline。
从客户端来看
1.数据从客户端发出到达Channel,该过程称为出站,反之由Channel到达客户端则称为入站;
2.出站会触发一系列OutBoundHandler处理,入站会触发InBoundHandler处理,我们经常使用的编码 Encoder 是出站操作,解码 Decoder 是入站操作。
从服务端来看
1.数据从Channel到达服务端,该过程称为入站,反之由服务端到达Channel则称为出站;
2.服务端接收到客户端数据后,需要先经过 Decoder 入站处理后,再通过 Encoder 出站通知客户端;
所以客户端和服务端一次完整的请求应答过程可以分为四个步骤:
- 客户端出站(请求数据)
- 服务端入站(解析数据并执行业务逻辑)
- 服务端出站(响应结果)
- 客户端入站(解析数据并执行业务逻辑)
InBoundHandler和OutBoundHandler的执行顺序如下图,进站时根据InBoundHandler的添加顺序执行,出站时OutBoundHandler则是逆序执行。

2、ChannelHandler 和 ChannelHandlerContext
每创建一个 Channel 都会绑定一个新的 ChannelPipeline,ChannelPipeline 中每加入一个 ChannelHandler 都会绑定一个 ChannelHandlerContext。由此可见,ChannelPipeline、ChannelHandlerContext、ChannelHandler 三个组件的关系是密切相关的。
ChannelHandlerContext 用于保存 ChannelHandler 上下文,通过 ChannelHandlerContext 我们可以知道 ChannelPipeline 和 ChannelHandler 的关联关系。ChannelHandlerContext 可以实现 ChannelHandler 之间的交互,ChannelHandlerContext 包含了 ChannelHandler 生命周期的所有事件,如 connect、bind、read、flush、write、close 等。
如下如图:

三、服务端主从Reactor模式工作流程
3.1 Server工作流程图

3.2 Server工作流程分析
1. server端启动时绑定本地某个端口,初始化NioServerSocketChannel。
2. 将自己NioServerSocketChannel注册到某个BossNioEventLoopGroup的selector上。
- server端包含1个Boss NioEventLoopGroup和1个Worker NioEventLoopGroup,
- Boss NioEventLoopGroup专门负责接收客户端的连接,Worker NioEventLoopGroup专门负责网络的读写
- NioEventLoopGroup相当于1个事件循环组,这个组里包含多个事件循环NioEventLoop,每个NioEventLoop包含1个selector和1个事件循环线程。
3. BossNioEventLoopGroup循环执行的任务:
- 轮询accept事件;
- 处理accept事件,将生成的NioSocketChannel注册到某一个WorkNioEventLoopGroup的Selector上。
- 处理任务队列中的任务,runAllTasks。任务队列中的任务包括用户调用eventloop.execute或schedule执行的任务,或者其它线程提交到该eventloop的任务。
4. WorkNioEventLoopGroup循环执行的任务:
- 轮询read和Write事件
- 处理IO事件,在NioSocketChannel可读、可写事件发生时,回调(触发)ChannelHandler进行处理。
- 处理任务队列的任务,即 runAllTasks
参考:
https://juejin.cn/post/7176589585042899004
https://cloud.tencent.com/developer/article/2146079
本文作者:MuXinu
本文链接:https://www.cnblogs.com/MuXinu/p/18091950
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步