普通流程
网络IO读写流程应用进程的每一次写操作,都会把数据写到用户空间的缓冲区中,再由 CPU 将数据拷贝到系统内核的缓冲区中,之后再由 DMA 将这份数据拷贝到网卡中,最后由网卡发送出去。这里我们可以看到,一次写操作数据要拷贝两次才能通过网卡发送出去,而用户进程的读操作则是将整个流程反过来,数据同样会拷贝两次才能让应用程序读取到数据。应用进程的一次完整的读写操作,都需要在用户空间与内核空间中来回拷贝,并且每一次拷贝,都需要 CPU 进行一次上下文切换(由用户进程切换到系统内核,或由系统内核切换到用户进程),这样是不是很浪费 CPU 和性能呢?那有没有什么方式,可以减少进程间的数据拷贝,提高数据传输的效率呢?
所谓的零拷贝,就是取消用户空间与内核空间之间的数据拷贝操作,应用进程每一次的读写操作,都可以通过一种方式,让应用进程向用户空间写入或者读取数据,就如同直接向内核空间写入或者读取数据一样,再通过 DMA 将内核中的数据拷贝到网卡,或将网卡中的数据 copy 到内核。
零拷贝有两种解决方式,分别是 mmap+write 方式和 sendfile 方式,mmap+write方式的核心原理就是通过虚拟内存来解决的。
mmap(Memory-mapped file)
mmap(Memory-mapped file)是一种在内存和文件之间建立映射关系的技术。它允许将文件的一部分或整个文件映射到进程的地址空间,使得进程可以像访问内存一样直接读写文件数据。 使用mmap技术进行文件映射,可以带来一些优势和灵活性: 1. 零拷贝操作:mmap技术避免了数据在内核空间和用户空间之间的拷贝,从而提高了文件I/O的效率。当进程访问映射区域时,数据直接在内存中进行读写,减少了不必要的数据复制操作。 2. 文件缓存:映射文件的数据可以利用操作系统的文件缓存机制。如果多个进程都映射了同一个文件,它们可以共享同一个缓存,减少了磁盘I/O的次数,提高了整体性能。 3. 随机访问:通过映射文件到内存,进程可以直接访问文件的任意部分,而无需按照顺序逐步读取。这使得随机访问文件变得更加高效。 4. 内存映射:映射文件到内存后,可以将文件视为一块连续的内存区域进行操作。这使得对文件的读写操作变得更加灵活和方便。
sendfile
数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer,同时,由于和用户态完全无关,就减少了一次上下文切换。
mmap 和 sendFile 的区别
- mmap 适合小数据量读写,sendFile 适合大文件传输。
- mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 2 次上下文切换,最少 2 次数据拷贝。
- sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket 缓冲区)。
在这个选择上:rocketMQ 在消费消息时,使用了 mmap。kafka 使用了 sendFile。
标签:文件,映射,mmap,内核,拷贝,数据 From: https://www.cnblogs.com/zhengbiyu/p/18242051