Netty
Netty
Netty 是一个异步、事件驱动的,用来做高性能、高可靠性的网络应用框架。
优点
- 框架设计优雅,底层模型随意切换适应不同的网络协议要求。
- 提供很多标准的协议、安全、编码解码的支持。
- 解决了很多 NIO 不易用的问题。
- 社区更为活跃,在很多开源框架中使用,如 Dubbo、RocketMQ、Spark 等。
功能、特性
- 底层核心有:Zero-Copy-Capable Buffer,非常易用的灵拷贝 Buffer;统一的 API;标准可扩展的时间模型
- 传输方面的支持有:管道通信;Http 隧道;TCP 与 UDP
- 协议方面的支持有:基于原始文本和二进制的协议;解压缩;大文件传输;流媒体传输;protobuf 编解码;安全认证;http 和 websocket
Netty 采用 NIO 而非 AIO 的理由
- Netty 不看重 Windows 上的使用,在 Linux 系统上,AIO 的底层实现仍使用 EPOLL,没有很好实现 AIO,因此在性 能上没有明显的优势,而且被 JDK 封装了一层不容易深度优化
- Netty 整体架构是 reactor 模型, 而 AIO 是 proactor 模型, 混合在一起会非常混乱,把 AIO 也改造成 reactor 模型看起 来是把 epoll 绕个弯又绕回来
- .AIO还有个缺点是接收数据需要预先分配缓存, 而不是NIO那种需要接收时才需要分配缓存, 所以对连接数量非常大 但流量小的情况, 内存浪费很多
- Linux 上 AIO 不够成熟,处理回调结果速度跟不到处理需求,比如外卖员太少,顾客太多,供不应求,造成处理速度 有瓶颈(待验证)
传统 RPC 调用性能差的三宗罪
- 同步阻塞 IO:传统的 RPC 框架或者基于 RMI 等方式的远程服务(过程)调用采用了同步阻塞 IO。
- 序列化方式问题:
- Java 序列化机制是 Java 内部的一种对象编解码技术,无法跨语言使用;例如对于异构系统之间的对接,Java 序列化 后的码流需要能够通过其它语言反序列化成原始对象(副本),目前很难支持;
- 相比于其它开源的序列化框架,Java 序列化后的码流太大,无论是网络传输还是持久化到磁盘,都会导致额外的资 源占用;
- 序列化性能差(CPU 资源占用高)。
- 线程模型问题:由于采用同步阻塞 IO,这会导致每个 TCP 连接都占用 1 个线程,由于线程资源是 JVM 虚拟机非常宝 贵的资源,当 IO 读写阻塞导致线程无法及时释放时,会导致系统性能急剧下降,严重的甚至会导致虚拟机无法创建新 的线程。
高性能的三个主题
- 传输:用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,IO 模型在很大程度上决定了框架的性能。
- 协议:采用什么样的通信协议,HTTP 或者内部私有协议。协议的选择不同,性能模型也不同。相比于公有协议, 内部私有协议的性能通常可以被设计的更优。
- 线程:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,Reactor 线程模型的不同, 对性能的影响也非常大。
Netty 高性能之道
异步非阻塞通信
- Netty 的 IO 线程 NioEventLoop 聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端 Channel,由于读 写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 IO 阻塞导致的线程挂起。
- 由于 Netty 采用了异步通信模式,一个 IO 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 IO 一 连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。
服务端通信
客户端通信