IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux内核零拷贝技术 -> 正文阅读

[系统运维]linux内核零拷贝技术

1. 设计思想

零拷贝技术主要用于磁盘数据通过网络进行交互,常见用法卸载磁盘文件从网络发送出去。常规的卸载文件方法流程如下所示。
在这里插入图片描述

从上图可以看出软件流程一共复制了4次数据,内核态到用户态切换4次。
读操作(复制两次,上下文切换两次):
1.用户进程通过 read() 函数向内核(kernel)发起系统调用,上下文从用户态(user space)切换为内核态(kernel space)
2.CPU利用DMA控制器将数据从主存或硬盘拷贝到内核空间(kernel space)的读缓冲区(read buffer)
3。CPU将读缓冲区(read buffer)中的数据拷贝到用户空间(user space)的用户缓冲区(user buffer)
4.上下文从内核态(kernel space)切换回用户态(user space),read 调用执行返回。
写操作(复制两次,上下文切换两次):
1.用户进程通过 write() 函数向内核(kernel)发起系统调用,上下文从用户态(user space)切换为内核态(kernel space)
2.CPU 将用户缓冲区(user buffer)中的数据拷贝到内核空间(kernel space)的网络缓冲区(socket buffer)
3.CPU 利用 DMA 控制器将数据从网络缓冲区(socket buffer)拷贝到网卡进行数据传输。(虽然网络驱动会分层解析网络数据帧,但网络数据是通过sk_buff指针缓存在各个层级进行数据,所以这里网络协议层不存数据拷贝)
4.上下文从内核态(kernel space)切换回用户态(user space),write 系统调用执行返
从上面可以看到用户态和内核态之间数据拷贝流程走了两次,熟悉linux内核调度结构的知道内核态和应用态数据拷贝是比较费时,同时拷贝数据是个冗余过程,仅仅从应用态过了一圈。所以引入了零拷贝技术。

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

mmap():
和传统的区别就是read操作变成了mmap,之后用户空间会和内核态共享同一块内核缓冲区,读入的数据都在这个内核缓冲区里面。写入的话还是和原来一样。这个函数在linux设计中用的比较多,结合/dev/mem使用可以直接在应用态访问硬件物理地址,或者将文件映射到内存等。

sendfile():
sendfile对于mmap来说更加优化了一步,数据从缓冲复制到到socket直接都是在内核空间一次性完成的,用户空间只是发起了sendfile的调用,减少了复制和上下文切换的开销。这个文件只能针对真正的文件从网络卸载,对于自定义文件系统是不支持的,对于高速存储用的比较少。

splice():
splice又在上面两位前辈的基础上变更更加强大,之前sendfile只能是内核缓冲区向socket复制数据,而splice直接让讷河缓冲区和socket之间建立了一个管道可以直接相互交换数据。
linux零拷贝技术本次采用的mmap+write方式实施,数据走向流程图如下所示。

在这里插入图片描述

将内核读缓存通过mmap函数映射到应用态,实现内核态和应用态共享该空间。通过mmap函数后会减少一次数据拷贝,上下文切换不变,但是通过异步设计思想可以规避掉上下文切换耗时。

2 代码设计

在内核态分配20个连续的DMA缓存空间,分别标号为1~20,读磁盘和通过网络发送数据实现异步方式,只要有空余的缓存空间,读线程一直读数据到20个缓存空间中,网络发送线程一直发送数据。读数据和发送数据通过循环队列实现,可以使用互斥锁实现循环队列,也可以使用无锁高效互斥队列。
2.1 mmap函数
zero_copy_vir_addr=mmap(NULL,zero_copy_block_size*zero_copy_block_num,PROT_READ|PROT_WRITE,MAP_SHARED,dev_fd,zero_copy_phy_addr);
if (zero_copy_vir_addr == NULL){
DBG_PRINTF("%s mmap fail!!\n",FUNCTION);
return -1;
}

zero_copy_phy_addr是内核态分配的DMA缓存空间的物理地址,注意需要保证cache一致性,该地址在程序初始化时通过ioctl查询到应用态使用,zero_copy_vir_addr是映射该物理地址得到的虚拟地址,在write socket函数中使用。

2.2 读磁盘函数

应用态通过计算需要读写的扇区,然后通过read函数将需要读写的扇区写到内核态,驱动read函数实现如下:
在这里插入图片描述

1.拷贝需要读取的扇区信息
2.计算可以使用的20个缓存中的ID值,并且填充SQ队列,将缓存地址填入到SQ的PRP中
3.数据读取完成,返回数据存放的ID值,读写队列控制在应用态控制

2.3 应用态读函数
在这里插入图片描述

应用态读线程函数计算需要读取的扇区信息,同时获取是否有空闲的DMA 缓存ID,如果没有就休眠,一直等到有空闲为止。GetCanUseWriteAddr函数就是用来判断是否有可以使用的DMA 缓存 ,网络发送函数中会释放DMA 缓存。

2.4 网络发送函数
在这里插入图片描述

SOLO_Read函数用于读取是否有可以使用的数据完成块,注意这个函数是非阻塞的,所以下面有usleep休眠,如果使用了pthread_mutex_lock+ pthread_cond_wait函数互斥的话,那就是阻塞方式获取空闲缓存,我使用的高效无锁互斥,牺牲CPU换取高性能。

3 总结
在linux零拷贝设计中,需要注意cache一致性问题。没有使用零拷贝技术,linux平台下网络卸载速率只有70MB/s,使用零拷贝技术速度可以到达107MB/s。(千兆网络link状态下),并且通过上位机验证数据正确。需要技术支持联系vx:yolov8。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:45:44  更:2021-11-22 12:45:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 0:20:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码