开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情
Netty核心组件
-
NioEventLoopGroup:事件循环组,本质上是一个经过包装的线程池,可以含有多个事件循环,每⼀个事件循环是 NioEventLoop,表示⼀个不断循环的执⾏处理任务的线程, -
NioEventLoop:每个 NioEventLoop 聚合了⼀个多路复用器 Selector,因此可以处理成百上千的客户端连接,Netty 的处理策略是每当有⼀个新的客户端接入,则从 NioEventLoopGroup 线程组中顺序获取⼀个可用的 NioEventLoop,当到达数组上限之后,重新返回到 0,通过这种方式,可以基本保证各个NioEventLoop 的负载均衡。Selector 可以注册监听多个 NioChannel,用于监听绑定在其上的 Socket 的网络通讯,而每个 NioChannel 只会绑定在唯⼀的 NioEventLoop 上。⼀个客户端连接只注册到⼀个 NioEventLoop 上,这样就避免了多个 IO 线程去并发操作它。
NioEventLoop 主要作用如下:
- 作为服务端 Acceptor 线程,负责处理客户端的请求接入;
- 作为客户端 Connecor 线程,负责注册监听连接操作位,⽤于判断异步连接结果;
- 作为 IO 线程,监听⽹络读操作位,负责从 SocketChannel 中读取报文;负责向 SocketChannel 写入报文发送给对方,如果发生写半包,会自动注册监听写事件,用于后续继续发送半包数据,直到数据全部发送完成;
- 作为定时任务线程,可以执⾏定时任务,例如链路空闲检测和发送心跳消息等;
- 作为线程执⾏器可以执⾏普通的任务线程 (Runnable)。
当系统在运行过程中,如果频繁的进行线程上下文切换,会带来额外的性能损耗。多线程并发执⾏某个业务流程,业务开发者还需要时刻对线程安全保持警惕,哪些数据可能会被并发修改以及如何保护。这不仅降低了开发效率,也会带来额外的性能损耗。为了解决上述问题,NioEventLoop 内部采用串行化设计,消息的读取、解码、处理、编码、发送,始终由 IO 线程 NioEventLoop 负责。这就意味着整个流程不需要进行上下文切换,数据也不会面临并发修改的风险,对于开发者而言,甚⾄不需要了解 Netty 的线程细节,直接调用 NioEventLoop 的 execute(Runnable task) 方法即可执行自定义的 Task
-
PipLine:每个 Worker NIOEventLoop 处理业务时,会使用 PipLine (管道) ,PipLine 中包含了 Channel,即通过 PipLine 可以获取到对应通道,管道中维护了很多的处理器。每个 NioChannel 都绑定有⼀个自己的 ChannelPipeline。