Netty逻辑架构图
Reactor 通信调度层
它由一系列辅助类组成,包括 Reactor 线程NioEventLoop 以及其父类、NioSocketChannel/NioServerSocketChannel 以及其父类、ByteBuffer 以及由其衍生出来的各种 Buffer、Unsafe 以及其衍生出的各种内部子类等。
该层的主要职责就是监听网络的读写和连接操作,负责将网络层的数据读取到内存缓冲区中,然后触发各种网络事件,列入连接创建、连接激活、读写事件等,将这些事件出发到PipeLine中,有PipeLine管理的职责连来进行后续的处理。
职责链ChannelPipeline
职责链Pipeline层。负责事件在职责链中有序的向前(后)传播,同时负责动态的编排职责链。Pipeline可以选择监听和处理自己关心的事件。不同的Handler节点功能不同。往往会开发编码解码Handler用于消息的编解码,可以将外部的协议消息转换成内部的POJO对象,这样上册业务层只需要关系业务处理即可,实现了架构层面的分层。
业务处理编排层
一般可分为两类:一类是纯粹的业务逻辑处理,例如日志、订单处理。一类是其他的应用层协议插件,用于特定协议相关的会话和链路管理,例如HTTP(S)协议、FTP协议等
Netty的关键架构质量属性
高性能
- 采用异步非阻塞的I/IO类库,基于Reactor模式实现,解决了传统同步阻塞I/O模式下一个服务端无法平滑地处理线性增长的客户端问题。
- TCP接收和发送缓冲区使用直接内存代替堆内存,避免了内存赋值,提升了I/O读取和写入的性能。
- 支持通过内存池的方式循环利用ByteBuf,避免了频繁创建和销毁ByteBuf带来的性能损耗。
- 可配置的I/O线程数、TCP参数等,为不同的用户场景提供定制化的调优参数,满足不同的场景。
- 采用环形数组缓冲区实现无锁化并发编程,代替传统的线程安全容器或者锁。
- 合理地使用线程安全容器、原子类等,提升系统并发处理能力
- 关键资源的处理使用单线程串行化的方式,避免多线程并发访问带来的锁竞争和额外的CPU资源消耗问题。
- 通过引用计数器及时地申请释放不再被引用的对象,细粒度的内存管理降低了GC的频率。
可靠性
链路检测有效性,为了保证长连接的链路有效性,支持心跳检测(学习笔记一中的心跳机制)。
内存保护机制:
对象引用计数器对Netty的ByteBuf等内置对象进行细粒度的内存申请和释放,对非法的对象引用进行检测和保护
通过内存池来重用ByteBuf,节省内存。
可设置的内存容量上限,包括ByteBuf、线程池线程数等。
优雅停机
当系统退出时,JVM通过注册的Shutdown Hook拦截到退出信号量,然后执行退出操作,释放相关模块的资源占用,将缓冲区的消息处理完成或者清空,将待刷新的数据持久化到磁盘或者数据库中,等到资源回收和缓冲区消息处理完成后,在退出。会设置一个最大的超时时间T,如果达到T后仍然没有退出,则通过kill -9 pid 强杀当前的进程。
可定制性
责任链模式的ChannelPipeline
基于接口开发,关键的类库都提供了接口或者抽象类
大量工厂类,通过重载这些工厂类可以按需创建出用户实现的对象
大量的系统参数供用户按需设置,增强系统的场景定制性
可扩展性
基于Netty的基础NIO,可以方便地进行应用层协议的定制,例如基于Netty的Http协议、Dubbo协议、RocketMQ内部私有协议等。
影响网络服务通信性能的主要因素有:网络I/O模型、线程(进程)调度模型和数据序列化方式
传输(I/O模型):用什么样的通道将数据发送给对方。
协议:采用什么样的通信协议,HTTP等共有协议或者内部私有协议。
线程:数据如何读取,读取之后的编解码在哪个线程进行,如何派发,Reactor线程模型的不同,对性能影响巨大。