标签:方式 ott code 做了 内存映射文件 关联 直接 ima buffer
零拷贝(Zero-Copy):一种高效的数据传输机制
从某台机器将一份数据通过网络传输到另一台机器,通过Java语言简单描述就是:
public static void transfer() throws IOException { Socket socket = new Socket(HOST, PORT); InputStream in = new FileInputStream(FILE_PATH); OutputStream out = new DataOutputStream(socket.getOutputStream()); byte[] buffer = new byte[1024]; while (in.read(buffer) != -1) { // 将数据写到 Socket out.write(buffer); } out.close(); socket.close(); in.close(); }
虽然代码操作看起来很简单,但是深入到操作系统层面,就会发现实际的微观操作相当复杂;具体步骤:
这个过程进行了四次上下文切换(模式切换),并且数据被来回拷贝了四次;但是真正消耗资源和浪费时间的是第2、3次;因为这两次都需要经过 CPU Copy 而且还需要内核态和用户态之间的来回切换。如果忽略系统的调用细节,整个过程可以通过下图表示:
上下文切换是CPU密集型的工作,数据拷贝是 I/O 密集型的工作
如果一次传输工作就像上面那样复杂的话,效率是相当低下的;零拷贝机制的目标就是消除冗余的上下文切换和数据拷贝,提高效率
替代原来的 read + write 方式,mmap 是一种内存映射文件的方式;mmap 通过内存映射,将文件映射到内核缓冲区;
同时,用户空间可以共享内核空间的数据(mmap 允许程序直接在用户态中访问内核空间中的数据,这样能避免一次无意义的 Copy);建立共享映射后,就不需要从内核缓冲区拷贝到用户缓冲区了,这就避免了一次拷贝了
|
sendfile() 系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高
Linux 2.1 版本提供了 sendFile() 函数:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer 中;同时由于完全和用户态无关,就减少了一次上下文切换
Linux 2.4 后,Socket 缓冲区做了调整,DMA 带收集功能,DMA 可以直接将内核缓冲区数据直接传输到协议引擎,消灭最后一次拷贝
|
基于此基础,RocketMQ 使用了 mmap;Kafka 使用了 sendFile()
标签:方式 ott code 做了 内存映射文件 关联 直接 ima buffer
原文地址:https://www.cnblogs.com/sebastian-tyd/p/13581192.html