1、基本概念
内核态和用户态
Linux OS 体系架构分为内核态和用户态,也叫用户空间和内核。
内核态:控制计算机的硬件资源,并提供上层应用程序运行的环境。
用户态:上层应用程序的活动空间,依托于内核提供的资源。
二者关系:
用户态(上层应用程序)通过系统调用内核态中的资源。
DMA
Direct Memory Access 直接存储器访问,不依赖CPU大量中断负载。
对比流程-图源网络。
不使用DMA技术时:
使用DMA后:
使用了DMA技术后,CPU的工作量大大减轻,此时io操作已有所提升,示意图如下。
应用了DMA技术后,io操作还是存在很多可优化的空间,比如频繁的用户态和内核态切换,多份数据缓冲区等。因此,引出了零拷贝技术。
2、 零拷贝技术
什么是零拷贝?
广义上的零拷贝:减少不必要的拷贝次数就可以叫做零拷贝技术。
比较:
传统io——阻塞、效率低。
零拷贝——不阻塞,cpu利用率高,效率快
下面介绍零拷贝的两种技术:
整体思路都是通过减少(用户态和内核态的)上下文切换和数据拷贝,来提高效率。
1、mmap
直接将内核缓冲区的数据映射到用户空间,使得内核态和用户态之间就不需要数据拷贝了。
总共存在两次系统调用:mmap和write。
具体步骤如下:
- 磁盘的数据拷贝到内核的缓冲区,通过DMA。
- OS将内核缓冲区的数据拷贝到内核态中的socket缓冲区。
- 内核的socket缓冲区的数据拷贝到网卡的缓冲区,通过DMA。
注:图源网络。
2、sendfile
特点:
完全在内核中操作,避免了数据在内核缓冲区和用户缓冲区的拷贝,大大提高了效率。
具体操作:
替代了mmap方式中的read()+write(),减少了一次系统调用。
3、 零拷贝技术应用
1、java的nio
java的nio的Channel就相当于操作系统中的内核缓冲区,有可能是读缓冲区,也有可能是网络缓冲区,而Buffer就相当于是用户缓冲区。
FileChannel类提供了mmap、sendfile这两种实现,map()就是采用了操作系统中的内存映射的方式实现的,底层就是调用的Linux mmap()。
//mmap,Maps a region of this channel's file directly into memory.
public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException;
transferTo()直接将当前通道内容传输到另一个通道,没有涉及Buffer的任何操作。就是通过Linux的sendfile()。
//sendfile
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;
public abstract long transferFrom(ReadableByteChannel src,
long position, long count)
throws IOException;
注意:
nio中的transferTo和transferFrom并不一定能使用零拷贝,这要取决于操作系统。
2、Kafka中的应用
应用场景:
生产者的数据存储到broker,消费者从broker读取数据。