Java知识分享网 - 轻松学习从此开始!    

Java知识分享网

Java1234官方群25:java1234官方群17
Java1234官方群25:838462530
        
SpringBoot+SpringSecurity+Vue+ElementPlus权限系统实战课程 震撼发布        

最新Java全栈就业实战课程(免费)

springcloud分布式电商秒杀实战课程

IDEA永久激活

66套java实战课程无套路领取

锋哥开始收Java学员啦!

Python学习路线图

锋哥开始收Java学员啦!
当前位置: 主页 > Java文档 > Java基础相关 >

高性能:零拷贝为什么能提升性能? PDF 下载


分享到:
时间:2023-03-19 10:05来源:http://www.java1234.com 作者:转载  侵权举报
高性能:零拷贝为什么能提升性能? PDF 下载
失效链接处理
高性能:零拷贝为什么能提升性能? PDF 下载


本站整理下载:
提取码:umpr 
 
 
相关截图:
 
主要内容:

零拷⻉字⾯上的意思包括两个,“零”和“拷⻉”:
“拷⻉” :就是指数据从⼀个存储区域转移到另⼀个存储区域。
“零” :表示次数为 0,它表示拷⻉数据的次数为 0。
合起来,那 零拷⻉ 就是不需要将数据从⼀个存储区域复制到另⼀个存储区域。
做服务端开发的⼩伙伴,⽂件下载功能应该实现过不少了吧。如果你实现的是⼀
个 Web 程序,前端请求过来,服务端的任务就是:将服务端主机磁盘中的⽂件
从已连接的 socket 发出去。关键实现代码如下:
传统的 IO 流程,包括 read 和 write 的过程。
read :把数据从磁盘读取到内核缓冲区,再拷⻉到⽤户缓冲区。
write :先把数据写⼊到 socket 缓冲区,最后写⼊⽹卡设备。
流程图如下:
⽤户应⽤进程调⽤ read 函数,向操作系统发起 IO 调⽤,上下⽂从⽤户态
转为内核态(切换 1)
DMA 控制器把数据从磁盘中,读取到内核缓冲区。
CPU 把内核缓冲区数据,拷⻉到⽤户应⽤缓冲区,上下⽂从内核态转为⽤户
态(切换 2),read 函数返回
⽤户应⽤进程通过 write 函数,发起 IO 调⽤,上下⽂从⽤户态转为内核态
(切换 3)
CPU 将应⽤缓冲区中的数据,拷⻉到 socket 缓冲区
DMA 控制器把数据从 socket 缓冲区,拷⻉到⽹卡设备,上下⽂从内核态切
换回⽤户态(切换 4),write 函数返回
从流程图可以看出,传统 IO 的读写流程,包括了 4 次上下⽂切换(4 次⽤户态和
内核态的切换),4 次数据拷⻉(两次 CPU 拷⻉以及两次的 DMA 拷⻉),什么
是 DMA 拷⻉呢?我们⼀起来回顾下,零拷⻉涉及的操作系统知识点哈。
我们电脑上跑着的应⽤程序,其实是需要经过操作系统,才能做⼀些特殊操作,
如磁盘⽂件读写、内存的读写等等。因为这些都是⽐较危险的操作,不可以由应
⽤程序乱来,只能交给底层操作系统来。
因此,操作系统为每个进程都分配了内存空间,⼀部分是⽤户空间,⼀部分是内
核空间。内核空间是操作系统内核访问的区域,是受保护的内存空间,⽽⽤户空
间是⽤户应⽤程序访问的内存区域。 以 32 位操作系统为例,它会为每⼀个进程
都分配了4G(2 的 32 次⽅)的内存空间。
内核空间 :主要提供进程调度、内存分配、连接硬件资源等功能
⽤户空间 :提供给各个程序进程的空间,它不具有访问内核空间资源的权
限,如果应⽤程序需要使⽤到内核空间的资源,则需要通过系统调⽤来完
成。进程从⽤户空间切换到内核空间,完成相关操作后,再从内核空间切换
回⽤户空间。
如果进程运⾏于内核空间,被称为进程的内核态
如果进程运⾏于⽤户空间,被称为进程的⽤户态。
什么是上下⽂?
什么是 CPU 上下⽂切换?
⼀般我们说的上下⽂切换,就是指内核(操作系统的核⼼)在 CPU 上对进程或
者线程进⾏切换。进程从⽤户态到内核态的转变,需要通过系统调⽤来完成。系
统调⽤的过程,会发⽣CPU 上下⽂的切换。
现代操作系统使⽤虚拟内存,即虚拟地址取代物理地址,使⽤虚拟内存可以有 2
个好处:
虚拟内存空间可以远远⼤于物理内存空间
多个虚拟内存可以指向同⼀个物理地址
正是多个虚拟内存可以指向同⼀个物理地址,可以把内核空间和⽤户空间的虚拟
地址映射到同⼀个物理地址,这样的话,就可以减少 IO 的数据拷⻉次数啦,示
意图如下
DMA,英⽂全称是 Direct Memory Access,即直接内存访问。DMA本质上是
⼀块主板上独⽴的芯⽚,允许外设设备和内存存储器之间直接进⾏ IO 数据传
输,其过程不需要 CPU 的参与。
我们⼀起来看下 IO 流程,DMA 帮忙做了什么事情.
⽤户应⽤进程调⽤ read 函数,向操作系统发起 IO 调⽤,进⼊阻塞状态,等
待数据返回。
CPU 收到指令后,对 DMA 控制器发起指令调度。
DMA 收到 IO 请求后,将请求发送给磁盘;
磁盘将数据放⼊磁盘控制缓冲区,并通知 DMA
DMA 将数据从磁盘控制器缓冲区拷⻉到内核缓冲区。
DMA 向 CPU 发出数据读完的信号,把⼯作交换给 CPU,由 CPU 负责将数
据从内核缓冲区拷⻉到⽤户缓冲区。
⽤户应⽤进程由内核态切换回⽤户态,解除阻塞状态
可以发现,DMA 做的事情很清晰啦,它主要就是帮忙 CPU 转发⼀下 IO 请求,
以及拷⻉数据。为什么需要它的?
零拷⻉并不是没有拷⻉数据,⽽是减少⽤户态/内核态的切换次数以及 CPU 拷⻉
的次数。零拷⻉实现有多种⽅式,分别是
mmap+write
sendfile
带有 DMA 收集拷⻉功能的 sendfile
mmap 的函数原型如下:
addr :指定映射的虚拟内存地址
length :映射的⻓度
prot :映射内存的保护模式
flags :指定映射的类型
fd : 进⾏映射的⽂件句柄
offset : ⽂件偏移量
前⾯⼀⼩节,零拷⻉相关的知识点回顾,我们介绍了虚拟内存,可以把内核空间
和⽤户空间的虚拟地址映射到同⼀个物理地址,从⽽减少数据拷⻉次数!mmap
就是⽤了虚拟内存这个特点,它将内核中的读缓冲区与⽤户空间的缓冲区进⾏映
射,所有的 IO 都在内核中完成。
mmap+write 实现的零拷⻉流程如下:
⽤户进程通过 mmap⽅法 向操作系统内核发起 IO 调⽤,上下⽂从⽤户态切
换为内核态。
CPU 利⽤ DMA 控制器,把数据从硬盘中拷⻉到内核缓冲区。
上下⽂从内核态切换回⽤户态,mmap ⽅法返回。
⽤户进程通过 write ⽅法向操作系统内核发起 IO 调⽤,上下⽂从⽤户态切
换为内核态。
CPU 将内核缓冲区的数据拷⻉到的 socket 缓冲区。
CPU 利⽤ DMA 控制器,把数据从 socket 缓冲区拷⻉到⽹卡,上下⽂从内
核态切换回⽤户态,write 调⽤返回。
可以发现, mmap+write 实现的零拷⻉,I/O 发⽣了4次⽤户空间与内核空间的
上下⽂切换,以及 3 次数据拷⻉。其中 3 次数据拷⻉中,包括了2 次 DMA 拷⻉
和 1 次 CPU 拷⻉。
mmap 是将读缓冲区的地址和⽤户缓冲区的地址进⾏映射,内核缓冲区和应⽤缓
冲区共享,所以节省了⼀次 CPU 拷⻉‘’并且⽤户进程内存是虚拟的,只是映射到
内核的读缓冲区,可以节省⼀半的内存空间。
sendfile 是 Linux2.1 内核版本后引⼊的⼀个系统调⽤函数,API 如下:
out_fd :为待写⼊内容的⽂件描述符,⼀个 socket 描述符。,
in_fd :为待读出内容的⽂件描述符,必须是真实的⽂件,不能是 socket
和管道。
offset :指定从读⼊⽂件的哪个位置开始读,如果为 NULL,表示⽂件
的默认起始位置。
count :指定在 fdout 和 fdin 之间传输的字节数。
sendfile 表示在两个⽂件描述符之间传输数据,它是在操作系统内核中操作
的,避免了数据从内核缓冲区和⽤户缓冲区之间的拷⻉操作,因此可以使⽤它来
实现零拷⻉。
sendfile 实现的零拷⻉流程如下:
1. ⽤户进程发起 sendfile 系统调⽤,上下⽂(切换 1)从⽤户态转向内核态
2. DMA 控制器,把数据从硬盘中拷⻉到内核缓冲区。
3. CPU 将读缓冲区中数据拷⻉到 socket 缓冲区
4. DMA 控制器,异步把数据从 socket 缓冲区拷⻉到⽹卡,
5. 上下⽂(切换 2)从内核态切换回⽤户态,sendfile 调⽤返回。
可以发现, sendfile 实现的零拷⻉,I/O 发⽣了2次⽤户空间与内核空间的上
下⽂切换,以及 3 次数据拷⻉。其中 3 次数据拷⻉中,包括了2 次 DMA 拷⻉和
1 次 CPU 拷⻉。那能不能把 CPU 拷⻉的次数减少到 0 次呢?有的,即 带有DMA
收集拷⻉功能的sendfile !
linux 2.4 版本之后,对 sendfile 做了优化升级,引⼊ SG-DMA 技术,其实就
是对 DMA 拷⻉加⼊了 scatter/gather 操作,它可以直接从内核空间缓冲区
中将数据读取到⽹卡。使⽤这个特点搞零拷⻉,即还可以多省去⼀次 CPU 拷
⻉。
sendfile+DMA scatter/gather 实现的零拷⻉流程如下:
1. ⽤户进程发起 sendfile 系统调⽤,上下⽂(切换 1)从⽤户态转向内核态
2. DMA 控制器,把数据从硬盘中拷⻉到内核缓冲区。
3. CPU 把内核缓冲区中的⽂件描述符信息(包括内核缓冲区的内存地址和偏移
量)发送到 socket 缓冲区
4. DMA 控制器根据⽂件描述符信息,直接把数据从内核缓冲区拷⻉到⽹卡
5. 上下⽂(切换 2)从内核态切换回⽤户态,sendfile 调⽤返回。
可以发现, sendfile+DMA scatter/gather 实现的零拷⻉,I/O 发⽣了2次
⽤户空间与内核空间的上下⽂切换,以及 2 次数据拷⻉。其中 2 次数据拷⻉都是
包DMA 拷⻉。这就是真正的 零拷⻉(Zero-copy) 技术,全程都没有通过 CPU
来搬运数据,所有的数据都是通过 DMA 来进⾏传输的。
Java NIO 对 mmap 的⽀持
Java NIO 对 sendfile 的⽀持
Java NIO 有⼀个 MappedByteBuffer 的类,可以⽤来实现内存映射。它的底层
是调⽤了 Linux 内核的mmap的 API。
mmap 的⼩ demo如下:
FileChannel 的 transferTo()/transferFrom() ,底层就是 sendfile() 系统
调⽤函数。Kafka 这个开源项⽬就⽤到它,平时⾯试的时候,回答⾯试官为什么
这么快,就可以提到零拷⻉ sendfile 这个点。
sendfile 的⼩ demo如下:
框架篇:⼩⽩也能秒懂的 Linux 零拷⻉原理
深⼊剖析 Linux IO 原理和⼏种零拷⻉机制的实现
阿⾥⼆⾯:什么是 mmap?
相关⾯试题 :
简单描述⼀下传统的 IO 执⾏流程,有什么缺陷?
什么是零拷⻉?
零拷⻉实现的⼏种⽅式
Java 提供的零拷⻉⽅式
作者:程序员⽥螺 ,公众号:捡⽥螺的⼩男孩
《Java ⾯试指北》已获授权并对其内容进⾏了完善。
1.什么是零拷⻉
零拷⻉是指计算机执⾏ IO 操作时,CPU 不需要将数据从⼀个存储区域复制到
另⼀个存储区域,从⽽可以减少上下⽂切换以及 CPU 的拷⻉时间。它是⼀种 I
/O 操作优化技术。
2. 传统 IO 的执⾏流程

------分隔线----------------------------

锋哥公众号


锋哥微信


关注公众号
【Java资料站】
回复 666
获取 
66套java
从菜鸡到大神
项目实战课程

锋哥推荐