前前后后利用工作之余的闲暇时间阅读Netty源码有一个月了,现在Netty各组件之间的联系,已经有了一个初步的认识。但文章还停留在笔记的整理阶段,只能当成个人笔记看。此文为Netty系列的第一篇,主要描述一个客户端请求在Netty中流转的整个生命周期,它经过了哪些组件之间相互配合。后面的文章会对每一个组件进行源码分析,以及此文没有体现出来的组件它们的作用。如
ChannelFuture
、ByteBuf
等。在阅读之前,推荐先阅读下之前的一篇文章(浅谈NIO中的Reactor设计模式应用)。
1. 回顾Ractor模型的Multiple Reactors Version
Ractor
模型的Multiple Reactors Version
是浅谈NIO中的Reactor设计模式应用中的3.3,DougLea在Scalable IO in Java
画的模型图如下所示:
mainReactor
的acceptor
只负责接收客户端的连接事件,subReactor
只负责网络
读写I/O
事件,其实subReactor
可以有多个,这样减轻每个subReactor
负载。对于耗时compute业务代码,可以交给线程池处理,处理后注册写事件返回给客户端。acceptor
和subReactor
都轮询自己的selector.select()
,处理着自己"感兴趣"的事件。其实Netty底层模型应用便是这种,只不过各组件的名字和作用都有些差异。
/**
* 举个例子:现在我想一个accptor和多个subReactor。
**/
// 一个Acceptor
EventLoopGroup parentEventLoopGroup = new NioEventLoopGroup(1);
// 当前CPU核数*2的subReactor个数,对于现在超线程CPU那就再*n
EventLoopGroup childEventLoopGroup = new NioEventLoopGroup();
复制代码
2. Netty中的各组件联系
2.1 请求在各组件间的流转图
2.2 图中Netty的各组件的作用
对于selector、channel等组件的作用可以在浅谈NIO中的Reactor设计模式应用,本文只介绍Netty相关的组件用途,以下内容根据图自顶向下
NioEventLoopGroup
:直译这个类名就是nio
的事件轮询组,其实轮询的就是Selector.select()
。文档中的解释是"it is used for NIO Selector based Channel."。对于接收客户端的连接事件与selectionKey绑定的是ServerSocketChannel;对于读写网络I/O
事件与selectionKey绑定的便是SocketChannel。NioEventLoop
:通过名称就可以看出来,它便是事件轮询组中的一个轮询,也就是一个subReactor
或者acceptor
(通常做法在创建接收连接的轮询组时都是创建一个)。ChannelPipeline
:文档中的解释是"it handles or intercepts inbound events and outbound operations of a implements an advanced form of the Intercepting Filter pattern",翻译过来就是它处理或者是拦截入栈事件和出栈的一些操作,实现了一种更加高级的拦截过滤器模式。过滤器模式是入出走同一个过滤器,而对于ChannelPipeline
入栈处理和出栈处理分离开了,ChannelPipeline
底层维护着一个ChannelHandlerContext
双向链表。ChannelPipeline
的处理流程如下: 从Channel
里读出来的数据,需要经过与Channel
绑定的ChannelPipeline
中的InboundHandler
处理,再注册写事件。写出的时候需要经ChannelPipeline
中的OutboundHandler
处理在写回给客户端。ChannelHandlerContext
:ChannelPipeline
中是ChannelHandlerContext
双向链表,它起到一个承上启下的作用,意思是能够向上获取到ChannelPipeline
和Channel
,又能向下获取到ChannelHandler
。ChannelInboundHandlerAdapter
/ChannelOutboundHandlerAdapter
:入栈出栈的处理器对象,它应用适配器设计模式,后续文章中我们在从细节分析。ServerBootStrapAcceptor
:Netty
中acceptor
对象,用于将EventLoop
中Selector
接收到的Channel
(这里面其实与selectionKey
绑定的是serverChannel
然后再通过serverChannel.accept()
得到的),将Channel
注册给ChildEventLoop
(这块Netty
是通过round-robin
去获取EventLoop
)中个其中一个Selector
上。