一.Netty高性能的原因总结:
1.基于I/O多路复用模型:
底层用的NIO技术,可以看我以前发过的一篇NIO介绍文章
https://blog.csdn.net/xc123_java/article/details/113992022
2.零拷贝
3.基于内存池的缓冲区重用机制
对于堆外直接内存的分配和回收,是一件耗时的操作,而且这些实例随着消息的处理朝生夕灭,这就会给服务器带来沉重的GC压力,同时消耗大量的内存。为了尽量重用缓冲区,Netty提供了基于内存池的缓冲区重用机制ByteBuf内存池.
4.无锁化的串行设计理念
从消息的读取->解码->处理->编码->发送,始终由IO线程NioEventLoop负责
5.I/O操作的异步处理和事件处理
有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers;这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handler,可以将处理event的Request handler实现一个单独的线程,这样Service Handler 和request Handler实现了异步
6.提供对protobuf等高性能序列化协议支持
7.可以对TCP进行更加灵活地配置
二.零拷贝技术:
1.零拷贝是指避免在用户态(User-space) 与内核态(Kernel-space) 之间来回拷贝数据的技术。
2.NIO零拷贝适用于以下场景:
文件较大,读写较慢,追求速度
JVM内存不足,不能加载太大数据
内存带宽不够,即存在其他程序或线程存在大量的IO操作,导致带宽本来就小
3.传统的IO读取数据并通过网络发送的流程
下面两次拷贝完成了读取数据的一次IO过程
第一次拷贝:read()调用,DMA引擎执行第一次拷贝:从文件读取数据并存储到内核空间的缓冲区。
第二次拷贝:read()调用返回,请求的数据从内核的读缓冲区拷贝到用户缓冲区,导致上下文从内核态切换到用户态
下面两次拷贝完成了发送数据的一次IO过程
第三次拷贝:send()调用,数据从用户空间重新拷贝到内核空间缓冲区。数据被写入一个不同的缓冲区,一个与目标套接字相关联的缓冲区.
第四次拷贝:DMA引擎将数据从内核套接字缓冲区传输到协议引擎
4.NIO的零拷贝:
简化掉了用户态和内核态之间的切换.数据拷贝从4次变为了3次,上下文切换次数从4次减少到了2次
5.Netty提供CompositeByteBuf类, 可以将多个ByteBuf合并为一个逻辑上的ByteBuf, 避免了各个ByteBuf之间的拷贝。
6.slice操作和wrap操作
Unpooled.wrappedBuffer可以将多个ByteBuf 合并为一个, 而slice操作可以将一个ByteBuf切片为多个共享一个存储区域的 ByteBuf对象