Netty零拷贝

1. 概述

零拷贝即Zero-copy,就是在操作数据时,不需要将数据buffer从一个内存区域拷贝到另一个内存区域,因为少了内存的拷贝,因此CPU的效率就得到提升。

在OS层面上的零拷贝,通常指避免在用户态与内核态之间来回拷贝数据。例如Linux提供的mmap系统调用,它可以将一段用户空间内存映射到内核空间,当映射成功后,用户对这段内存区域的修改可以直接反映到内核空间;同样的,内核空间对这段区域的修改也直接反映到用户空间。正因为有这样的映射关系,我们就不需要在用户态与内核态之间拷贝数据,提高了数据传输的效率。

需要注意的是,Netty中的Zero-copy与我们上面所提到的OS层面Zero-copy不太一样,Netty的Zero-copy完全是在用户态(Java层面)的,它的Zero-copy的更多是偏向于优化数据操作这样的概念。

Netty的零拷贝体现在如下几个方面

  • Netty提供了CompositeByteBuf类,它可以将多个ByteBUf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝
  • 通过wrap操作,我们可以将byte[]数组、ByteBuf、ByteBuffer等包装成一个Netty ByteBuf对象进而避免了拷贝操作
  • ByteBuf支持slice操作,因此可以将ByteBuf分解为多个共享同一存储区域的ByteBuf,避免了内存的拷贝
  • 通过FileRegion包装的FileChannel.tranferTo实现文件传输,可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。
2. 通过 CompositeByteBuf 实现零拷贝

假设我们有一份协议数据, 它由头部和消息体组成, 而头部和消息体是分别存放在两个 ByteBuf 中的, 即:

ByteBuf header = ...
ByteBuf body = ...

我们在代码处理中, 通常希望将 header 和 body 合并为一个 ByteBuf, 方便处理, 那么通常的做法是:

ByteBuf allBuf = Unpooled.buffer(header.readableBytes() + body.readableBytes());
allBuf.writeBytes(header);
allBuf.writeBytes(body);

可以看到, 我们将 header 和 body 都拷贝到了新的 allBuf 中了, 这无形中增加了两次额外的数据拷贝操作了.

那么有没有更加高效优雅的方式实现相同的目的呢? 我们来看一下 CompositeByteBuf 是如何实现这样的需求的吧:

ByteBuf header = ...
ByteBuf body = ...

CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
compositeByteBuf.addComponents(true, header, body);

addComponents方法将 header 与 body 合并为一个逻辑上的 ByteBuf, 即:
在这里插入图片描述

不过需要注意的是, 虽然看起来 CompositeByteBuf 是由两个 ByteBuf 组合而成的, 不过在 CompositeByteBuf 内部, 这两个 ByteBuf 都是单独存在的, CompositeByteBuf 只是逻辑上是一个整体
上面 CompositeByteBuf 代码还以一个地方值得注意的是, 我们调用addComponents(boolean increaseWriterIndex, ByteBuf… buffers) 来添加两个 ByteBuf, 其中第一个参数是 true, 表示当添加新的 ByteBuf 时, 自动递增 CompositeByteBuf 的 writeIndex,如果我们调用的是:

compositeByteBuf.addComponents(header, body);

那么其实 compositeByteBuf 的 writeIndex 仍然是0, 因此此时我们就不可能从 compositeByteBuf 中读取到数据, 这一点希望大家要特别注意.
除了上面直接使用 CompositeByteBuf 类外, 我们还可以使用 Unpooled.wrappedBuffer 方法, 它底层封装了 CompositeByteBuf 操作, 因此使用起来更加方便:

ByteBuf header = ...
ByteBuf body = ...

ByteBuf allByteBuf = Unpooled.wrappedBuffer
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值