零拷贝技术和kafka中的应用

本文深入探讨了零拷贝技术,介绍了Linux中传统服务器数据传输的低效流程,阐述了零拷贝技术如何通过减少数据拷贝次数和系统调用来提升性能。文章详细解释了零拷贝的三种分类,包括直接I/O、避免程序和内核间拷贝及优化拷贝过程,并以Kafka为例,展示了零拷贝技术在实际应用中的显著效果。

Zero Copy

一、Linux中传统服务器进行数据传输的流程

  • 传统的Linux 操作系统的标准 I/O 接口是基于数据拷贝操作的,即 I/O 操作会导致数据在操作系统内核地址空间的缓冲区和应用程序地址空间定义的缓冲区之间进行传输。这样做最大的好处是可以减少磁盘 I/O 的操作,因为如果所请求的数据已经存放在操作系统的高速缓冲存储器中,那么就不需要再进行实际的物理磁盘 I/O 操作。但是数据传输过程中的数据拷贝操作却导致了极大的 CPU 开销,限制了操作系统有效进行数据传输操作的能力。
  • 图1

在这里插入图片描述

  • 如图所示我们看到,应用程序读取磁盘数据然后发送到网卡需要四次拷贝的过程,OS采用DMA技术与硬件交互,应用程序需要2次系统调用,因此对于高性能的程序来说由性能损失。(DMA是一种硬件和软件之间的数据传输的技术,且DMA进行数据传输的过程中几乎不需要CPU参与),下面是自己画的一个数据走向流程图。
  • 图2

在这里插入图片描述

二、什么是零拷贝?

  • 简单一点来说,零拷贝就是一种避免CPU 将数据从一块存储拷贝到另外一块存储的技术。
    针对操作系统中的设备驱动程序、文件系统以及网络协议堆栈而出现的各种零拷贝技术极大地提升了特定应用程序的性能,并且使得这些应用程序可以更加有效地利用系统资源。这种性能的提升就是通过在数据拷贝进行的同时,允许 CPU 执行其他的任务来实现的。零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率。而且,零拷贝技术减少了用户应用程序地址空间和操作系统内核地址空间之间因为上下文切换而带来的开销。进行大量的数据拷贝操作其实是一件简单的任务,从操作系统的角度来说,如果 CPU 一直被占用着去执行这项简单的任务,那么这将会是很浪费资源的;如果有其他比较简单的系统部件可以代劳这件事情,从而使得 CPU 解脱出来可以做别的事情,那么系统资源的利用则会更加有效。综上所述,零拷贝技术的目标可以概括如下:
避免数据拷贝
  • 避免操作系统内核缓冲区之间进行数据拷贝操作。
  • 避免操作系统内核和用户应用程序地址空间这两者之间进行数据拷贝操作。
  • 用户应用程序可以避开操作系统直接访问硬件存储。
  • 数据传输尽量让 DMA 来做。
将多种操作结合在一起
  • 避免不必要的系统调用和上下文切换。
  • 需要拷贝的数据可以先被缓存起来。
  • 对数据进行处理尽量让硬件来做。

三、零拷贝技术分类

直接 I/O
  • 应用程序可以直接访问硬件存储,操作系统内核只是辅助数据传输。这类零拷贝技术针对的是数不需要OS内核处理的情况,数据可以在应用程序地址空间的缓冲区和磁盘之间直接进行传输,不需要 Linux 操作系统内核提供的页缓存的支持,如下图的5和6箭头所示。
  • 图3

在这里插入图片描述

避免程序和内核间的拷贝
  • 数据传输时避免数据在OS内核缓冲区和应用程序的缓冲区之间拷贝。有时候应用程序不需要在数据传输的过程中访问数据,那么数据从Linux 的页缓存拷贝到用户进程的缓冲区中就可以完全避免,
    数据在页缓存中可以得到处理。在某些特殊的情况下,这种零拷贝技术可以获得较好的性能。Linux 中提供类似的系统调用主要有 mmap(),sendfile() 以及 splice(),如下图的1-5-4流程所示。
  • 图4

在这里插入图片描述

优化程序和内核间的拷贝
  • 对数据在 Linux 的页缓存和用户进程的缓冲区之间的传输过程进行优化。该零拷贝技术侧重于灵活地处理数据在用户进程的缓冲区和操作系统的页缓存之间的拷贝操作。这种方法延续了传统的通信方式,但是更加灵活。在Linux中,该方法主要利用了写时复制技术。这样的方式相当于保留了之前1-2-3-4的流程,只是对2,3的步骤进行了优化。

四、Kafka中的零拷贝

  • 在上面的第二种零拷贝技术,就是避免了程序和内核之间的零拷贝,其中sendfile()系统调用也是kafka所采用的方法。kafka中大量使用了OS的页缓存,生产者的消息很多都缓存在页缓存中,消费者从kafka中拉取消息时,消息如果在OS系统页缓存中命中的话,就不需要去磁盘加载消息了,而Kafka大量使用了OS的页缓存,这样设计使得消费时缓存命中非常高,这也是kafka高性能的一个原因。如下我们对比零拷贝在kafka中带来的性能优化。

  • 正常情况,数据从文件传输到socket的公共数据路径(如图2所示):

 操作系统将数据从磁盘读入到内核空间的页缓存
 应用程序将数据从内核空间读入到用户空间缓存中(系统调用)
 应用程序将数据写回到内核空间的socket缓存中(系统调用)
 操作系统将数据从socket缓冲区复制到网卡缓冲区,以便将数据经网络发出
  • 这样做明显是低效的,这里有四次拷贝,两次系统调用。按照图2的流程,命中缓存之后需要走2-3-4的流程到网卡,(如果没有命中,就需要走1-2-3-4的流程了)。2和3这两个拷贝的过程是需要耗费CPU的,在大量请求的场景下,积少成多,浪费了不少性能。如果使用sendfile,再次拷贝可以被避免:允许操作系统将数据直接从页缓存发送到网络上。所以在这个优化的路径中,只有最后一步将数据拷贝到网卡缓存中是需要的,类似于图4中的流程。

五、参考:

Kafka 中,零拷贝技术被广泛应用以提高消息传输的效率,特别是在从磁盘读取消息并发送到网络时。Kafka 的高性能高吞吐量在很大程度上依赖于对操作系统底层特性的利用,其中包括 Linux 的 `sendfile()` 系统调用,它正是实现零拷贝的核心机制。 --- ### 🧩 Kafka零拷贝应用场景 Kafka 的核心功能是将数据持久化到磁盘,并通过网络将数据高效地传输给消费者。在这个过程中,**当消费者从 Kafka broker 读取数据时**,Kafka 利用了零拷贝技术来减少不必要的内存拷贝上下文切换。 --- ### 🔍 零拷贝Kafka 中的工作流程(基于 Linux) 传统方式(非零拷贝): 1. 数据从磁盘加载到内核空间缓冲区。 2. 内核将数据复制到用户空间缓冲区(JVM 堆内存)。 3. 数据再次复制回内核空间,通过 socket 发送到网络。 4. 总共发生 **两次内存拷贝** **两次上下文切换**。 零拷贝方式(Kafka 使用): 1. 数据从磁盘加载到内核空间缓冲区。 2. 使用 `sendfile()` 系统调用直接将数据从内核缓冲区发送到 socket。 3. 数据不经过用户空间,仅一次上下文切换一次内存拷贝。 --- ### 📦 Kafka 如何使用 Java NIO 实现零拷贝Kafka 在底层使用了 Java NIO 的 `FileChannel.transferTo()` 方法,该方法在底层会尽可能调用操作系统的 `sendfile()`: ```java FileChannel fileChannel = new RandomAccessFile("data.log", "r").getChannel(); SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("consumer", 9092)); // 零拷贝传输:数据从文件通道直接传输到网络通道 fileChannel.transferTo(position, size, socketChannel); ``` - Kafka 的日志段(LogSegment)管理中,每个分区的消息都存储为一组按偏移量分段的日志文件。 - 当消费者请求特定偏移量范围内的消息时,Kafka 只需定位到对应的日志文件,然后通过 `transferTo()` 直接发送到网络通道。 --- ### ⚙️ Kafka 零拷贝带来的性能优势 | 优势 | 描述 | |------|------| | 减少 CPU 使用率 | 避免了多次数据复制,降低 CPU 负载 | | 提高吞吐量 | 更快地处理大量并发消费者的请求 | | 降低延迟 | 减少了上下文切换内存拷贝的时间开销 | --- ### ✅ Kafka 架构设计如何配合零拷贝 - **顺序写入磁盘**:Kafka 将消息追加写入磁盘,充分利用磁盘的顺序访问速度。 - **页缓存(Page Cache)**:Linux 操作系统自动将频繁访问的文件缓存在内存中,Kafka 利用这一点避免每次都访问磁盘。 - **批量发送与压缩**:虽然零拷贝不适合加密或压缩,但 Kafka 支持在应用层进行批量压缩后再传输。 --- ### 🚫 注意事项 - 零拷贝适用于大块数据传输,不适合需要中间处理(如加密、修改内容)的场景。 - Windows 上的 Java 并不完全支持 `transferTo()` 的零拷贝特性,因此 Kafka 推荐部署在 Linux 环境中以获得最佳性能。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值