零拷贝工作底层原理

零拷贝(Zero-copy)技术是一种计算机操作系统中用于提高数据传输效率的优化策略。在传统的数据传输过程中,需要将数据从一个缓冲区拷贝到另一个缓冲区,然后再传输给目标。这涉及到多次的 CPU 和内存之间的数据拷贝操作,会消耗 CPU 的时间和内存带宽。而零拷贝技术通过直接共享数据的内存地址,避免了中间的拷贝过程,从而提高了数据传输的效率。

零拷贝是如何实现的?

1、MMap

MMap(Memory Map)是 Linux 操作系统中提供的一种将文件映射到进程地址空间的一种机制,通过 MMap 进程可以像访问内存一样访问文件,而无需显式的复制操作。

传统的 IO 需要四次拷贝和四次上下文(用户态和内核态)切换,而 MMap 只需要三次拷贝和四次上下文切换,从而能够提升程序整体的执行效率,并且节省了程序的内存空间。

 2、senFile 方法

3、带有 scatter/gather 的 sendfile方式

scatter/gather 的 sendfile 只有两次数据复制(都是 DMA COPY)及 2 次上下文切换。CUP COPY 已经完全没有。不过这一种收集复制功能是需要硬件及驱动程序支持的。

4、splice 方式 

splice 调用和sendfile 非常相似,用户应用程序必须拥有两个已经打开的文件描述符,一个表示输入设备,一个表示输出设备。与sendfile不同的是,splice允许任意两个文件互相连接,而并不只是文件与socket进行数据传输。对于从一个文件描述符发送数据到socket这种特例来说,一直都是使用sendfile系统调用,而splice一直以来就只是一种机制,它并不仅限于sendfile的功能。也就是说 sendfile 是 splice 的一个子集。

在 Linux 2.6.17 版本引入了 splice,而在 Linux 2.6.23 版本中, sendfile 机制的实现已经没有了,但是其 API 及相应的功能还在,只不过 API 及相应的功能是利用了 splice 机制来实现的。

和 sendfile 不同的是,splice 不需要硬件支持。

哪些地方用到了零拷贝技术?

在 Java 中,以下几个地方使用了零拷贝技术:

  • NIO(New I/O)通道:java.nio.channels.FileChannel 提供了 transferTo() 和 transferFrom() 方法,可以直接将数据从一个通道传输到另一个通道,例如从文件通道直接传输到 Socket 通道,整个过程无需将数据复制到用户空间缓冲区,从而实现了零拷贝。
  • Socket Direct Buffer:在 JDK 1.4 及更高版本中,Java NIO 支持使用直接缓冲区(DirectBuffer),这类缓冲区是在系统堆外分配的,可以直接由网卡硬件进行 DMA 操作,减少数据在用户态与内核态之间复制次数 ,提高网络数据发送效率。
  • Apache Kafka 或者 Netty 等高性能框架:这些框架在底层实现上通常会利用 Java NIO 的上述特性来优化数据传输,如 Kafka 生产者和消费者在传输消息时会用到零拷贝技术以提升性能。

为什么使用零拷贝?

无论是传统的 I/O 方式,还是引入了零拷贝之后,2 次 DMA copy是都少不了的。因为两次 DMA 都是依赖硬件完成的。所以,所谓的零拷贝,都是为了减少 CPU copy 及减少了上下文的切换。

CPU拷贝DMA拷贝系统调用上下文切换
传统方法22read/write4
内存映射12mmap/write4
sendfile12sendfile2
scatter/gather copy02sendfile
splice02splice0

为什么零拷贝的两次DMA不能省略?

在计算机系统中,DMA(Direct Memory Access)是用于在外设(如硬盘、网卡)和内存之间高效传输数据的一种技术。即便是零拷贝技术,也无法绕过两次 DMA 拷贝。

1、从设备到内存的传输(第一次 DMA 拷贝)

外设(如硬盘)上的数据必须通过 DMA 控制器传输到内存中,CPU 才能处理或转发这些数据。这是硬件工作机制决定的,因为内存是 CPU 和外设之间共享的高速缓存区。

2、从内存到设备的传输(第二次 DMA 拷贝)

在数据被传递到网卡等设备发送出去时,数据需要从内存再次通过 DMA 控制器传输到网卡的缓冲区。这是因为网卡等外设通常没有直接访问主存的权限,需要通过 DMA 将数据搬运到其自身的发送缓冲区中。

零拷贝的其他实现

1、splice() 系统调用

  • splice() 是 Linux 提供的一种系统调用,用于在两个文件描述符之间高效传输数据,避免了用户态和内核态之间的切换。
  • 数据直接在内核缓冲区中传输,减少了用户态的参与。
  • 常用于管道和文件之间的数据传输。

2、tee() 系统调用

  • tee() 用于在管道之间复制数据,而不实际消耗 CPU 或内存。
  • 数据不会真正拷贝,只是增加了引用计数。

3、IO Uring(Linux Kernel 5.1+)

  • IO Uring 是一种现代异步 IO 接口,通过共享环形缓冲区,在用户态和内核态之间减少数据拷贝和上下文切换。
  • 支持零拷贝操作,如网络数据发送等。

4、DMA-BUF

  • DMA-BUF 是一种跨设备的共享缓冲区机制,允许多个硬件设备共享同一块内存区域,减少数据拷贝。
  • 典型场景:图形处理中的 GPU 和显示设备共享数据。

5、RDMA(Remote Direct Memory Access)

  • RDMA 是一种高性能网络技术,允许数据直接从一个主机的内存传输到另一个主机的内存,而无需经过 CPU。
  • 常用于分布式系统和高性能计算领域。

零拷贝的关键点

零拷贝的目标是尽可能减少:

  • 数据从用户态到内核态的拷贝
  • 数据在内存中的多次搬运

但 DMA 传输过程无法绕过,零拷贝的主要优化点是避免 CPU 和用户态的额外参与,实现更高的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值