系列教程:
- Netty系列教程(一)Netty是什么: juejin.cn/post/714169…
- Netty系列教程(二)Netty架构设计剖析:juejin.cn/post/714191…
- Netty系列教程(三)Netty组件之EventLoopGroup:juejin.cn/post/714197…
- Netty系列教程(四)Netty组件之Channel通道:juejin.cn/post/714232…
- Netty系列教程(五)Netty组件之ChannelPipeline与ChannelHandler:juejin.cn/post/714232…
Netty整体架构
这是一张Netty官网关于Netty的核心架构图:
netty架构图
可以看到Netty由以下三个核心部分构成:
-
传输服务:传输服务层提供了网络传输能力的定义和实现方法。它支持 Socket、HTTP 隧道、虚拟机管道等传输方式。Netty 对 TCP、UDP 等数据传输做了抽象和封装,用户可以更聚焦在业务逻辑实现上,而不必关系底层数据传输的细节。\
-
协议支持:Netty支持多种常见的数据传输协议,包括:HTTP、WebSocket、SSL、zlib/gzip、二进制、文本等,还支持自定义编解码实现的协议。Netty丰富的协议支持降低了开发成本,基于 Netty 我们可以快速开发 HTTP、WebSocket 等服务。\
-
Core核心:Netty的核心,提供了底层网络通信的通用抽象和实现,包括:可扩展的事件驱动模型、通用的通信API、支持零拷贝的Buffer缓冲对象。\
Netty逻辑架构
Netty采用典型的三层网络架构进行设计和开发,其逻辑架构如图:
netty逻辑架构
网络通信层
网络通信层的职责主要是监听网络的读写和连接操作,负责将网络层的数据读取到内存缓冲区中,然后触发各种网络事件,如连接创建、连接激活、读事件、写事件等,这些网络事件会分发给事件调度层进行处理。
网络通信层的核心组件有:
-
Bootstrap:启动引导,主要负责整个Netty程序的启动、初始化、服务器连接等过程,它相当于一条主线,把Netty的其他核心组件给串联起来。Netty中的引导器分为两种:Bootstrap:客户端启动引导,另一种是ServerBootstrap:服务端启动引导。它们都继承自抽象类 AbstractBootstrap。\
-
Channel:网络通信的载体,提供了基本的用于I/O操作的API,如:register、bind、connect、read、write、flush等。Netty的Channel是在JDK的NIO Channel基础上进行封装的,提供了更高层次的抽象,同时屏蔽了底层Socket的复杂性,赋予了Channel更加强大的功能。\
事件调度层
事件调度层的职责是通过 Reactor 线程模型对各类事件进行聚合处理,通过 Selector 主循环线程集成多种事件( I/O 事件、信号事件、定时事件等),实际的业务处理逻辑是交由服务编排层中相关的 Handler 完成。
事件调度层的核心组件有:
-
EventLoopGroup
-
EventLoop
EventLoopGroup本质上是一个线程池,主要负责接收I/O请求,并分配线程处理请求。一个EventLoopGroup包含一个或者多个EventLoop,EventLoop用于处理Channel生命周期内的所有I/O事件,如accept、read、write等。
EventLoop同一时间会与一个线程绑定,每个EventLoop负责处理多个Channel。
每新建一个Channel,EventLoopGroup会选择一个EventLoop与其绑定,该Channel生命周期内都可以对EventLoop进行多次绑定和解绑。
服务编排层
负责组装各类服务,它是Netty的核心业务处理链,用于实现网络事件的动态编排和有序传播。
服务编排层的核心组件有:
-
ChannelPipeline:handler处理器链列表,也可以说是容器,内部通过双向链表将不同的ChannelHandler串联在一起,当I/O读写事件发生时,ChannelPipeline会依次调用ChannelHandler列表对Channel的数据进行拦截处理。每个Channel创建时就会绑定一个新的ChannelPipeline,他们是一一对应的关系。
-
ChandlerHandler:事件业务处理器顶层接口,它不处理入站和出站事件,而是由其子类来实现,核心子类包括:
-
-
ChannelInboundHandler:负责处理入站事件,以及用户自定义事件
-
ChannelOutboundHandler:负责处理出站事件
-
ChannelDuplexHandler:同时实现了ChannelInboundHandler和ChannelOutboundHandler两个接口,既可以处理入站事件,也可以处理出站事件
-
-
ChannelHandlerContext:ChandlerHandler的上下文对象,在调用ChandlerHandler方法时,都会传入该上下文对象,ChannelHandlerContext 包含了 ChannelHandler 生命周期的所有事件,如 connect、bind、read、flush、write、close 等。
由于Netty的分层架构设计合理、优雅,因此,基于Netty开发的各种服务器程序才会越来越多。
Netty架构特点
高性能
Netty有着极高的性能,能够轻松应对高并发场景,并保证性能,这得益于它优良精细的架构设计,如果一个产品的架构设计得不好,无论开发如何努力,都很难开发出一个高性能、高可用的产品。
Netty通过如下设计,来保证系统的高性能:
IO模型
用什么样的通道将数据发送给对方,I/O 模型在很大程度上决定了框架的性能。
典型的有三种IO模型分别是BIO、NIO、AIO,Netty采用的是NIO模型来实现。具体三种IO模型的区别在第一章中有介绍。
Netty的IO线程NioEventLoop由于聚合了多路复用器Selector,可以同时处理成百上千个客户端连接。
当线程从某客户端socket通道进行读写数据时,若没有数据读写事件,则该线程可以处理其他任务,线程通常将非阻塞的IO的空闲时间用于其他通道上执行I/O操作,所以单独的线程可以管理多个输入和输出通道。
由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起。
一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。
线程模型
Netty采用的是Reactor线程模型,常见的Reactor线程模型有:
-
单Reactor单线程模型
-
单Reactor多线程模型
-
主从Reactor多线程模型
Netty主要基于主从Reactor多线程模型来实现其线程模型,主Reactor主要负责客户端的连接请求,并将请求转发给从Reactor;从Reactor主要负责响应通道的IO读写请求。
netty线程模型
内存优化
TCP接收和发送缓冲区使用直接内存代替堆内存,避免了内存复制,避免了GC带来的性能开销,提升了IO读取和写入的性能。
多线程优化
采用环形数组缓冲区实现无锁化并发编程,代替传统的线程安全容器或者锁。并且关键资源的处理使用 单线程串行化方式,避免多线程并发访问带来的锁竞争和额外的CPU资源消耗问题。
高可靠性
链路有效性检测
由于长链接不需要每次发送消息都创建链路,也不需要在消息交互完成时关闭链路,因此相对于短链接性能更高。为了保证长链接的链路有效性, 往往需要通过心跳机制周期性地进行链路检测,当链路失效时,可以及时关闭链路。
当有业务消息时,无需心跳检测,可以通过业务进行链路检测。所以心跳检测只需要在链路空闲时发挥作用。
为了支持心跳检测,Netty提供了如下三种链路空闲检测机制:
-
读空闲超时机制:当连续周期T没有消息可读时,触发超时handler,用户可以基于读空闲超时发送心跳消息,进行链路检测
-
写空闲超时机制:当连续周期T没有消息要发送时,触发超时handler,用户可以基于写空闲超时发送心跳消息,进行链路检测
-
读写空闲超时机制:当连续周期T没有消息要读/写时,触发超时handler,用户可以基于写空闲超时发送心跳消息,进行链路检测,其中只要读或者写任意一个达到条件就可以触发超时handler
Netty API提供了灵活的心跳超时检测配置能力,用户可以配置超时策略、超时参数、以及对应的处理逻辑。
内存保护机制
Netty提供了多种机制来对内存进行保护,包括以下几个方面:
-
通过对象引用计数器对Netty的ByteBuffer等内置对象进行细粒度的内存申请和释放,对非法的对象引用进行检测和保护
-
通过内存池来重用ByteBuffer,节省内存
-
可设置的内存容量上限,包括ByteBuf、线程池线程数等
优雅停机
优雅停机功能指当前系统退出时,JVM通过注册的Shutdown Hook拦截到退出信号量,然后执行退出操作,释放相关模块的资源占用,将缓冲区的消息处理完或者清空,将待刷新的数据持久化到磁盘或者数据库中,等到资源回收和缓冲区消息处理完成之后再退出。
Netty在所有涉及到资源回收和释放的地方都增加了优雅退出的方法,比如:
//关闭资源
bossGroup.shutdownGracefully();
高可扩展性
API中提供了大量的扩展点
Netty的API设计时,提供了大量的扩展点,方面用户扩展自定义的逻辑处理,包括:
-
责任链模式:ChannelPipeline基于责任链模式开发,便于业务逻辑拦截定制扩展
-
基于接口的开发:关键的类库都提供了接口或者抽象类,如果Netty自身的实现无法满足需求,可以自定义实现相关接口\
-
提供了大量工厂类,通过重载这些工厂类可以按需创建出用户实现的对象
-
提供了大量的系统参数供用户按需设置, 增强系统的场景定制能力
多种协议支持
Netty支持各种主流的应用协议,如HTTP、FTP、WebSocket等,也可以基于Netty的二进制类库实现协议的扩展和定制。
目前存在大量基于Netty框架开发的协议,如:Dubbo协议、RocketMQ内部私有协议等。