Netty:高性能之道

1.RPC调用性能模型分析

传统RPC调用性能差的三宗罪

1.网络传输方式问题。传统的RPC框架或者基于RMI等方式的远程服务调用采用了同步阻塞I/O,当客户端的并发压力大或者网络延时增大之后,同步阻塞I/O会由于频繁的wait导致I/O线程经常性的阻塞,由于线程无法高效工作,I/O处理能力自然下降。

采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端连接,接收客户端连接之后,为其创建一个新的线程处理请求消息,处理完成之后,返回应答消息给客户端,线程销毁,这就是一请求一应答模型。该架构最大的问题就是不具备弹性伸缩能力,当并发访问量增大后,服务端的线程个数和并发访问数成线性正比,由于线程是Java虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能急剧下降,随着并发量的继续增加,可能会发生句柄溢出,线程堆栈溢出等问题,并导致最终宕机。

2.序列化差,Java序列化性能差

3.线程模型问题。采用同步阻塞I/O模型,导致每个TCP连接都占用一个线程。一请求一应答模型。

2.Netty高性能之道

1.异步非阻塞通信:在I/O编程过程中,当需要处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理。

2.高效的Reactor线程模型,主从多线程模型。

3.无锁化串行设计

4.高效的并发编程

5.高性能的序列化框架

6.零拷贝

Netty的零拷贝主要体现在如下三方面:

第一种情况:Netty的接收和发送ByteBuffer采用Direct Buffers,使用堆外直接内存进行socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(Heap Buffer)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息发送过程中多了一次缓冲区的内存拷贝。

第二种零拷贝:CompositeByteBuf,它对外将多个ByteBuf封装成一个ByteBuf,对外提供统一封装后的ByteBuf接口。

第三种零拷贝:文件传输,Netty文件传输类DefaultFileRegion通过transferTo方法将文件发送到目标Channel中。

很多操作系统直接将文件缓冲区的内容发送到目标Channel中,而不需要通过循环拷贝的方式,这是一种更加高效的传输方式,提升了传输性能,降低了CPU和内存占用,实现了文件传输的“零拷贝”。

7.内存池

随着JVM虚拟机和JIT即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区Buffer,情况却稍有不同,特别是堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty提供了基于内存池的缓冲区重用机制。

Netty:高性能之道

备注:文章参考《Netty权威指南》,作者:李林锋。