Netty-13 Netty架构
一、Netty架构
Netty采用了三层网络架构进行设计和开发,架构图如下:
(一)Reactor通信调度层
Netty的最底层是Reactor通信调度层,它通过一系列的辅助类,包括Reactor线程NioEventLoop及其父类。NioSocketChannel、NIOServerSocketChannel及其父类。ByteBuffer及其衍生出来的各种Buffer,UnSafe及其衍生的各种内部类等等。该层的主要职责就是监听网络的读写和连接操作,负责将网络层的数据读取到内存缓冲区,然后出发各种事件,如创建链路、读写事件等等。将这些事件触发到PipeLine中,由PipeLine管理的职责连进行后续的处理。
(二)职责链ChannelPipeline
它负责事件在职责链中的有序传播,同时负责动态的编排职责链,职责连可以选择和监听自己关心的事件。它负责拦截处理和向后/前传播事件。通常情况下,Handler大概有两类,一类是负责把协议消息和POJO对象进行相互转换的,一类是进行纯粹的业务编码的。
(三)业务逻辑层(Service Handler)
业务逻辑层通常有两类:一类是纯粹的业务逻辑编排;一类是其他的应用层协议插件,如CMPP协议,用于管理和中国移动短信系统的对接。
二、 Netty架构的特点
(一)高性能
影响产品性能的因素:
- 架构不合理;
- 编码实现不合理,如死锁等;
- 服务器硬件配置太低;
- 带宽、磁盘IOPS等导致的I/O性能;
Netty基于以下方案实现了高性能:
- 采用异步非阻塞的I/O类库,基于Reactor模型实现,解决了BIO模式下一个服务器无法平滑的处理客户端数量线性增长的问题;
- TCP接受和发送缓冲区使用直接内存代替堆内存,避免了内存复制,提高了I/O读取和写入的性能;
- 支持通过内存池的方式循环利用ByteBuf,避免了频繁创建和销毁ByteBuf带来的性能损耗;
- 可配置的I/O线程数、TCP参数等,为不同的场景提供不同的定制化方案,满足不能的性能场景。
- 采用环形缓冲区实现无锁化并发编程,代替传统的线程安全器或者锁;
- 合理的使用线程安全器、原子类等,提高系统的并发能力;
- 关键资源的处理使用单线程串行模式,避免因为多线程造成的锁竞争和额外的CPU消耗;
- 通过引用计数器及时的申请释放不再需要使用的资源,降低GC频率。
(二)可靠性
- 链路有效性监测
- 由于长链接不需要每次发送消息都建立连接,也不用完成之后关闭链路,所以性能上比短连接要高。
- 为了保证长链接的有效性,往往需要通过心跳机制周期性的进行链路监测。当链路没有消息传送的时候,如果链路被关闭了,等到有业务的时候,需要进行重连,影响性能。通过心跳机制,一旦发现断开,进行重连。
- Netty有两种链路空闲监测机制:
a. 读空闲超时机制:当连续周期T没有消息要发送时,触发超时Handler。用户可以通过读空闲超时心跳消息,进行链路检测。如果连续N个周期仍然没有读取到心跳信息,可以主动关闭链路。
b.写空闲超时机制:当连续周期T没有消息可读时,触发超时Handler。用户可以通过读空闲超时心跳消息,进行链路检测。如果连续N个周期仍然没有接受到对方心跳信息,可以主动关闭链路。
- 内存保护机制
Netty通过多个方面对内存进行保护。
- 通过对象引用计数器对ByteBuf等内置对象进行细粒度的申请和释放;
- 通过内存池重用ByteBuf,节省内存;
- 可设置的内存容量上限,包括ByteBuf、线程池数量等。通过设置单个ByteBuf的最大长度,可以限制解码错位发生的码流过长问题。
- 优雅停机
Netty提供了一些方法用于优雅的退出系统,当系统退出的时候,JVM通过注册的Shutdown Hook拦截到退出信号量,从而执行退出操作,释放相关的资源。如:
- EventExecutorGroup.shutdownGracefully
- Unsafe.close
(三)可定制性
Netty的可定制性主要取决于以下几点:
- 责任链模式:ChannelPipeline基于责任链模式开发,便于业务逻辑的拦截、定制和扩展;
- 基于接口的开发:关键的类库都提供了接口和抽象类,当Netty自身实现无法满足要求的时候,用户可以自己去进行扩展;
- 提供了大量工厂类,通过重载这些工厂类,可以按需创建出用户实现的对象;
(四)可扩展性
基于Netty协议可以方便的进行应用层协议定制,如HTTP协议、FTP协议等等。这些协议不需要修改netty源码,只需要基于Netty的二进制类库即可实现。