1,Netty简述
- Netty 是一个基于 JAVA NIO 类库的异步通信框架,用于创建异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性的网络客户端和服务器端
- RPC高性能分析,请参考文章“【总结】RPC性能之道 ”
- 特点
-
- 异步、非阻塞、基于事件驱动的NIO框架
- 支持多种传输层通信协议,包括TCP、UDP等
- 开发异步HTTP服务端和客户端应用程序
- 提供对多种应用层协议的支持,包括TCP私有协议、HTTP协议、WebSocket协议、文件传输等
- 默认提供多种编解码能力,包括Java序列化、Google的ProtoBuf、二进制编解码、Jboss marshalling、文本字符串、base64、简单XML等,这些编解码框架可以被用户直接使用
- 提供形式多样的编解码基础类库,可以非常方便的实现私有协议栈编解码框架的二次定制和开发
- 经典的ChannelFuture-listener机制,所有的异步IO操作都可以设置listener进行监听和获取操作结果
- 基于ChannelPipeline-ChannelHandler的责任链模式,可以方便的自定义业务拦截器用于业务逻辑定制
- 安全性:支持SSL、HTTPS
- 可靠性:流量整形、读写超时控制机制、缓冲区最大容量限制、资源的优雅释放等
- 简洁的API和启动辅助类,简化开发难度,减少代码量
- 为什么不是传统的IO
-
- 线程模型存在致命缺陷:一连接一线程的模型导致服务端无法承受大量客户端的并发连接
- 性能差:频繁的线程上下文切换导致 CPU 利用效率不高
- 可靠性差:由于所有的 IO 操作都是同步的,所以业务线程只要进行 IO 操作,也会存在被同步阻塞的风险,这会导致系统的可靠性差,依赖外部组件的处理能力和网络的情况
- 使用NIO,同步阻塞 IO 的三个缺陷都将迎刃而解
-
- NIO 采用 Reactor 模式,一个 Reactor 线程聚合一个多路复用器 Selector,它可以同时注册、监听和轮询成百上千个 Channel,一个 IO 线程可以同时并发处理N个客户端连接,线程模型优化为1:N(N < 进程可用的最大句柄数)或者 M : N (M通常为 CPU 核数 + 1, N < 进程可用的最大句柄数)
- 由于 IO 线程总数有限,不会存在频繁的 IO 线程之间上下文切换和竞争,CPU 利用率高
- 所有的 IO 操作都是异步的,即使业务线程直接进行 IO 操作,也不会被同步阻塞,系统不再依赖外部的网络环境和外部应用程序的处理性能
- 切换到 NIO 编程之后可以为系统带来巨大的可靠性、性能提升,所以,目前采用 NIO 进行通信已经逐渐成为主流
- 为什么不直接使用JDK NIO类库
-
- NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
- 需要具备其它的额外技能做铺垫,例如熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的NIO程序
- 可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大
- JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7版本该问题仍旧存在,只不过该bug发生概率降低了一些而已,它并没有被根本解决
- 一个高性能、高可靠性的 NIO 服务端开发和维护成本都是非常高的,开发者需要具有丰富的 NIO 编程经验和网络维护经验,很多时候甚至需要通过抓包来定位问题
- 开发出一套 NIO 程序需要 1 个月,但是它的稳定很可能需要 1 年甚至更长的时间
- Netty 的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指
2,Netty原理
- Netty逻辑架构
-
- 第一层
-
- Reactor 通信调度层,它由一系列辅助类组成,包括 Reactor 线程NioEventLoop 以及其父类、NioSocketChannel/NioServerSocketChannel 以及其父类、ByteBuffer 以及由其衍生出来的各种 Buffer、Unsafe 以及其衍生出的各种内部子类等
- 第二层
-
- 职责链 ChannelPipeLine,它负责调度事件在职责链中的传播,支持动态的编排职责链,职责链可以选择性的拦截自己关心的事件,对于其它IO操作和事件忽略,Handler同时支持inbound和outbound事件
- 第三层
-
- 业务逻辑编排层,业务逻辑编排层通常有两类:一类是纯粹的业务逻辑编排,还有一类是应用层协议插件,用于协议相关的编解码和链路管理,例如 CMPP 协议插件
- 灵拷贝
-
- “零拷贝”是指计算机操作的过程中,CPU不需要为数据在内存之间的拷贝消耗资源。而它通常是指计算机在网络上发送文件时,不需要将文件内容拷贝到用户空间(User Space)而直接在内核空间(Kernel Space)中传输到网络的方式
- Netty的“零拷贝”主要体现在三个方面
-
- Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝
-