参考 http://www.infoq.com/cn/articles/netty-high-performance
参考 http://www.importnew.com/17647.html
1. 传统 RPC 调用性能差的三宗罪
1)网络传输方式问题
2)序列化方式问题
3)线程模型问题
2.高性能的三个主题
1) 传输方式:用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,IO 模型在很大程度上决定了框架的性能。
2) 传输协议及序列化:采用什么样的通信协议,HTTP 或者内部私有协议。协议的选择不同,性能模型也不同。相比于公有协议,内部私有协议的性能通常可以被设计的更优。
3) 线程模型:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发,Reactor 线程模型的不同,对性能的影响也非常大。
3. Netty 高性能之道
1. 异步非阻塞通信
NIO模型
2. 零拷贝
Netty 的“零拷贝”主要体现在如下三个方面:
1) Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行 Socket 读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行 Socket 读写,JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才写入 Socket 中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
2) Netty 提供了组合 Buffer 对象,可以聚合多个 ByteBuffer 对象,用户可以像操作一个 Buffer 那样方便的对组合 Buffer 进行操作,避免了传统通过内存拷贝的方式将几个小 Buffer 合并成一个大的 Buffer。
3) Netty 的文件传输采用了 transferTo 方法,它可以直接将文件缓冲区的数据发送到目标 Channel,避免了传统通过循环 write 方式导致的内存拷贝问题。
3.内存池
随着 JVM 虚拟机和 JIT 即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区 Buffer,情况却稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty 提供了基于内存池的缓冲区重用机制。
4.高效的 Reactor 线程模型
常用的 Reactor 线程模型有三种,分别如下:
1) Reactor 单线程模型;
2) Reactor 多线程模型;
3) 主从 Reactor 多线程模型
5. 无锁化的串行设计理念
在大多数场景下,并行多线程处理可以提升系统的并发性能。但是,如果对于共享资源的并发访问处理不当,会带来严重的锁竞争,这最终会导致性能的下降。为了尽可能的避免锁竞争带来的性能损耗,可以通过串行化设计,即消息的处理尽可能在同一个线程内完成,期间不进行线程切换,这样就避免了多线程竞争和同步锁。
为了尽可能提升性能,Netty 采用了串行无锁化设计,在 IO 线程内部进行串行操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎 CPU 利用率不高,并发程度不够。但是,通过调整 NIO 线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列 – 多个工作线程模型性能更优。
Netty 的串行化设计工作原理图如下:
图 2-25 Netty 串行化工作原理图
6. 高效的并发编程
Netty 的高效并发编程主要体现在如下几点:
1) volatile 的大量、正确使用 ;
2) CAS 和原子类的广泛使用;
3) 线程安全容器的使用;
4) 通过读写锁提升并发性能。
7. 高性能的序列化框架
影响序列化性能的关键因素总结如下:
1) 序列化后的码流大小(网络带宽的占用);
2) 序列化 & 反序列化的性能(CPU 资源占用);
3) 是否支持跨语言(异构系统的对接和开发语言切换)。
Netty 默认提供了对 Google Protobuf 的支持,通过扩展 Netty 的编解码接口,用户可以实现其它的高性能序列化框架,例如 Thrift 的压缩二进制编解码框架。
8. 灵活的 TCP 参数配置能力
合理设置 TCP 参数在某些场景下对于性能的提升可以起到显著的效果,例如 SO_RCVBUF 和 SO_SNDBUF。如果设置不当,对性能的影响是非常大的。下面我们总结下对性能影响比较大的几个配置项:
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/2450.html