【Netty】Netty的零拷贝原理与应用

IO中的零拷贝

内存的用户空间和内核空间

内存中有用户空间提供给用户调用

内存中内核空间给操作系统的指令使用

DMA 直接存储访问

DMA:直接存储访问,即不会经过CPU的运算,直接由DMA总线进行拷贝

当我们执行read(new byte[10])时,发送的调用过程

image-20210422073059921

上下文切换

是指CPU执行用户进程执行时处于用户态,当用户进程调用系统函数时,CPU中断用户执行,切换为内核态,执行系统指令。

普通的文件传输方式

普通的方式需要4次上下文切换、2次DMA拷贝、2次CPU运算拷贝

image-20210427003842615

内存映射(MMAP)方式

MMAP的方式就在CPU拷贝上做了一次优化,把内核的内存空间进行映射,映射到内存的用户空间上,这样对用户空间的操作实际是在对内核空间做操作。

image-20210427011412869

Linux的sendFile()优化

Linux2.1的方式

sendFile()为Linux2.1后增加的系统函数,sendfile系统调用的引入,不仅减少了数据复制,还减少了上下文切换的次数

Linux2.4的方式

这还不是最后效果呢,Linux为了消除内核产生的数据冗余,就是CPU拷贝会产生一些数据副本,提出了一个可以在多块内存空间发拷贝给网卡,所以需要网卡支持聚合操作特性。这个特性意味着待发送的数据可以不用存在地址连续的内存空间中,可以分散存放。

具体做法是在内核版本2.4中,socket缓冲区描述符结构发生了改动,以适应聚合操作的要求——这就是Linux中所谓的"零拷贝“。这种方式不仅减少了多个上下文切换,而且消除了数据冗余。

所以需要提升是2个前提的

  1. 支持聚合操作的硬件可以从多个内存位置收集数据,从而消除另一个副本。
  2. Linux对socket的缓冲区描述符进行改动,以支持聚合操作

image-20210427074825998

NIO中的零拷贝

内存

堆内存

在NIO中

ByteBuffer heapBuffer = ByteBuffer.allocate(n);

在Netty中

ByteBuf heapBuf = Unpooled.buffer(n);
特点:
  • 优点:在用户态使用声明和访问的时候速度更快
  • 缺点:在数据传输到外部时,要进行用户空间到内核空间的一次CPU运算拷贝,

堆外内存

通过mmap的方式声明堆外内存

在NIO中

ByteBuffer directBuffer = ByteBuffer.allocateDirect(n);

在Netty中

ByteBuf directBuf = Unpooled.buffer(n);
特点:
  • 优点:数据传输到外部时,不需要进行用户空间到内核空间的拷贝
  • 缺点:声明和访问会慢一点

文件传输

  1. sendFile方式
FileChannel channel = new RandomAccessFile(file_name, "rw").getChannel();
FileChannel copyChannel = new RandomAccessFile(copy_name, "rw").getChannel();
copyChannel.transferFrom(channel, 0, channel.size());
channel.close();
copyChannel.close();
  1. mmap方式
FileChannel channel = new RandomAccessFile(file_name, "rw").getChannel();
FileChannel copyChannel = new RandomAccessFile(copy_name, "rw").getChannel();
MappedByteBuffer mapped = channel.map(FileChannel.MapMode.READ_WRITE, 0, channel.size());
copyChannel.write(mapped);
copyChannel.transferFrom(channel, 0, channel.size());
channel.close();
copyChannel.close();

Netty中的零拷贝

内存:

和NIO一样的,Netty也有2种内存:

ByteBuf directBuf = Unpooled.directBuffer(1024);
ByteBuf heapBuf = Unpooled.buffer(1024);

image-20210427232421266

img

通过debug窗口可以查看heapBuf和directBuf最明显的区别就是有一个数组,数组是存储在堆中的。

文件传输

在Netty中既能通过mmap的方式,也能通过transfer(sendFile)的方式传输文件。

  1. sendFile方式

Netty中提供了FileRegion实现零拷贝传输文件的,底层就是调用了sendFile,在应用层就是以transfer的字眼出现。

 RandomAccessFile file = new RandomAccessFile(fileName, "rw");
 FileRegion fileRegion = new DefaultFileRegion(file.getChannel(),0,file.length());
 ctx.writeAndFlush(fileRegion);
  1. mmap方式
 RandomAccessFile file = new RandomAccessFile(fileName, "rw"); 
 MappedByteBuffer map = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
 ByteBuf byteBuf = Unpooled.wrappedBuffer(map);
 ctx.writeAndFlush(byteBuf);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值