图文详解io_uring高性能异步IO架构

说到高性能网络编程,我们第一时间想到的是epoll机制,epoll很长一段时间统治着整个网络编程江湖,然而io_uring的出现,似乎在撼动epoll的统治地位,今天我们来揭开io_uring的神秘面纱。

1.io_uring简介

io_uring是一个Linux内核的异步I/O框架,它提供了高性能的异步I/O操作,io_uring的目标是通过减少系统调用和上下文切换的开销来提高I/O操作的性能。

io_uring通过使用环形缓冲区和事件驱动的方式来实现高效的异步I/O操作。

io_uring的设计使得应用程序可以同时处理大量的I/O操作,从而提高系统的吞吐量和响应速度。

2.io_uring实现原理

io_uring整体架构如下:

2.1基础概念

  • SQE:提交队列项,表示IO请求。

  • CQE:完成队列项,表示IO请求结果。

  • SQ:Submission Queue,提交队列,用于存储SQE的数组。

  • CQ:Completion Queue,完成队列,用于存储CQE的数组。

  • SQ Ring:SQ环形缓冲区,包含SQ,头部索引(head),尾部索引(tail),队列大小等信息。

  • CQ Ring:CQ环形缓冲区,包含SQ,头部索引(head),尾部索引(tail),队列大小等信息。

  • SQ线程:内核辅助线程,用于从SQ队列获取SQE,并提交给内核处理,并将IO请求结果生成CQE存储在CQ队列。

2.2 io_uring系统调用

  • io_uring_setup():用于初始化io_uring环境,创建io_uring实例。

  • io_uring_enter():用于提交和等待io_uring操作的系统调用,可以指定提交的操作数量和等待的超时时间。

  • io_uring_register():用于注册文件描述符或事件文件描述符到io_uring实例中,以便进行I/O操作。

2.3 liburing库

liburing是一个用于Linux的用户空间库,用于利用io_uring接口进行高性能的异步I/O操作,它提供了一组函数和数据结构,使开发者能够更方便地使用io_uring接口。

  • io_uring_queue_init:初始化一个io_uring队列。

  • io_uring_register:将文件描述符注册到io_uring队列中。

  • io_uring_prep_read:准备一个读取操作。

  • io_uring_prep_write:准备一个写入操作。

  • io_uring_submit:提交一个或多个操作到io_uring队列中。

  • io_uring_wait_cqe:等待一个完成的操作。

  • io_uring_cqe_seen:标记一个完成的操作已经被处理。

  • io_uring_queue_exit:关闭并释放io_uring队列。

2.4 工作流程

  1. 创建io_uring对象:首先,需要创建一个io_uring对象,可以使用io_uring_setup()函数来完成。

  2. 准备I/O请求:在进行I/O操作之前,需要准备相关的I/O请求。可以使用io_uring_prep_XXX()系列函数来准备不同类型的I/O请求,例如io_uring_prep_read()用于读取数据,io_uring_prep_write()用于写入数据。

  3. 提交I/O请求:准备好I/O请求后,可以使用io_uring_submit()函数将请求提交给内核,内核会将这些请求放入一个队列中,等待执行。

  4. 等待IO请求完成:可以使用io_uring_wait_cqe()函数来等待I/O请求的完成,一旦请求完成,内核会将完成事件放入一个完成队列中。

  5. 获取IO请求结果:可以使用io_uring_peek_cqe()函数来获取完成队列中的完成事件。然后,可以通过事件的信息来处理完成的I/O请求,例如读取数据或者处理错误。

  6. 释放IO请求结果:获取完IO请求结果,使用io_uring_cqe_seen()函数来释放IO请求结果,以便内核可以继续使用。

  7. 重复执行:可以重复执行上述步骤,以处理更多的I/O请求。

3.内核实现

3.1 创建io_uring对象

用户程序通过io_uring_setup系统调用创建和初始化io_uring对象,io_uring对象对应于struct io_ring_ctx结构体对象。

io_uring_setup主要工作:

  • 创建struct io_ring_ctx对象并初始化。

  • 创建struct io_urings对象并初始化,注意此时已完成CQ和所有CQE创建。

  • 创建SQ和所有SQE并初始化。

  • 如果struct io_ring_ctx对象flags参数设置IORING_SETUP_SQPOLL,则创建SQ线程。

3.2 fd绑定io_uring对象

已创建的io_ring对象需要和fd进行绑定, 以便能够通过fd找到io_uring对象,创建一个新的file,file private_data成员指向io_ring对象,申请一个未使用的文件描述符fd,fd映射至file,并存储在进程已打开文件表中。

注意:mmap内存映射需要用到该fd。

相关视频推荐

linux c/c++开发之高性能网络编程,面试与开发都非常重要的技术,不容错过!(tcp/ip、udp、epoll、网络io、reactor、网络协议栈)icon-default.png?t=N7T8https://www.bilibili.com/video/BV1Ru4y1J7E3/

Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)

需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

3.3 io_uring对象内存映射

通过io_uring_setup系统调用创建完io_uring对象后,用户程序还不能直接访问io_uring对象,此时用户程序需要通过mmap函数将io_uring对象SQ,CQ以及head和tail等相关内存空间映射出来。

完成mmap内存映射后,io_uring对象相关内存空间成为用户程序和内核共享内存空间,用户程序可以直接访问io_uring对象,不再需要通过执行系统调用访问,很大程度上提高了系统性能。

3.4 提交IO请求

SQ Ring中有两个成员head(头部索引)和tail(尾部索引),头部索引指向SQ队列第一个已提交IO请求,尾部索引指向SQ下一个空闲SQE。

提交IO请求,只需要将tail指向的SQE填充IO请求信息,并让tail自增1,指向下一个空闲SQE。

注意:head和tail不是直接指向SQ数组,而是需要通过head&mask和tail &mask操作指向SQ数组,mask数组为数组长度减1,因为数组有固定大小,所以需要通过&mask方式防止越界访问数组,这种方式可以让数组形成一个环形缓冲区。

3.5 等待IO请求完成

IO请求的处理有两种方式:

  • 方式1:SQ线程从SQ队列中获取SQE(已提交IO请求),并发送给内核处理。

  • 方式2:用户程序通过io_uring_enter系统调用从SQ队列中获取SQE(已提交IO请求),并发送给内核处理。

从SQ队列获取SQE只需要获取SQ Ring head指向的SQE,并让head自增指向下一个SQE即可。

内核处理完IO请求后,SQ线程会申请CQ Ring tail指向的CQE存储IO请求结果,tail自增1指向下一个空闲CQE。

3.6 获取IO请求结果

用户程序通过判断CQ Ring head和tail之间的差值,可以检测到是否有已完成IO请求,如果有已完成IO请求(CQE),获取CQ Ring head指向CQE,获取IO请求结果。

3.7 释放已完成IO请求

释放已完成IO请求只需要将CQ Ring head指针自增1指向下一个CQE即可,这样做的目的是防止重复获取IO请求结果。

io_uring为什么高效?

核心原因:io_uring通过mmap内存映射大大减少了系统调用,在高并发场景下,系统调用非常损耗系统性能。

其他原因:

  • 减少拷贝:io_uring通过共享内存减少用户程序和内核数据拷贝。

  • 批量操作:io_uring支持批量操作,一次性可以提交多个I/O请求,减少系统调用的次数,提高系统效率。

  • 无锁环形队列:io_uring采用无锁队列实现用户程序与内核对共享内存的高效访问。

总结

io_uring是一个媲美epoll的高性能网络编程架构,从原理上分析也验证了这一点,io_uring值得多花点时间研究

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/758047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

竞赛 - 基于机器视觉的图像拼接算法

前言 图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要。 再举一个身边的例子吧,…

express+mysql+vue,从零搭建一个商城管理系统16--收货地址(全国省市县名称和code列表)

提示:学习express,搭建管理系统 文章目录 前言一、新建config/area.js二、新建models/address.js三、新建dao/address.js四、新建routes/address.js五、添加地址六、查询用户地址列表总结 前言 需求:主要学习express,所以先写serv…

浅谈大模型“幻觉”问题

大模型的幻觉大概来源于算法对于数据处理的混乱,它不像人类一样可以by the book,它没有一个权威的对照数据源。 什么是大模型幻觉 大模型的幻觉(Hallucination)是指当人工智能模型生成的内容与提供的源内容不符或没有意义的现象。…

SpringCloud Gateway工作流程

Spring Cloud Gateway的工作流程 具体的流程: 用户发送请求到网关 请求断言,用户请求到达网关后,由Gateway Handler Mapping(网关处理器映射)进行Predicates(断言),看一下哪一个符合…

windows docker

写在前面的废话 最近在学习riscv的软件相关内容,倒是有别人的sg2042机器可以通过ssh使用,但是用起来太不方便了,经常断掉,所以想着在自己的机器上跑一跑riscv的操作系统。最常见的有两种方法吧,第一个就是qemu&#xf…

数据库运行状况和性能监控工具

数据库监控是跟踪组织中数据库的可用性、安全性和性能的过程,它涉及通过跟踪各种关键指标来分析数据库的性能,确保数据库的正常运行并具有深入的可见性,并在出现潜在问题时触发即时警报,以采取主动措施来确保数据库的高可用性。 …

制定工业物联网战略? 成功的5个关键考虑因素

随着越来越多的公司争夺注意力和收入,成功和创造、建设和创新的压力也在增加,这导致了对工业物联网战略的更大需求。 随着越来越多的公司争夺注意力和收入,成功和创造、建设和创新的压力也在增加,这导致了对工业物联网战略的更大需…

一招让你的Mac重获新生,CleanMyMac助你轻松清理无用垃圾!

一招让你的Mac重获新生,CleanMyMac助你轻松清理无用垃圾! 告别卡顿,让你的Mac跑得更快更稳! 在当今这个快节奏的生活中,我们的工作和生活早已离不开电脑。特别是对于Mac用户来说,一台轻巧、快捷、稳定的Mac…

java算法第28天 | 93.复原IP地址 78.子集 90.子集II

93.复原IP地址 思路: 这里startIndex为插入‘.’的位置,使用回溯法遍历所有插入的位置,直接在原始字符串上操作。要注意的是开闭区间的规定(这里我规定的是左闭右闭区间)。还要明确什么时候能return。 class Solution…

HTML中的常用标签用法总结(持续更新...)

&#x1f31f; 欢迎来到 我的博客&#xff01; &#x1f308; &#x1f4a1; 探索未知, 分享知识 !&#x1f4ab; 本文目录 1. 标题标签2. 段落标签3. 链接标签4. 列表标签5. 图像标签6. 表格标签 1. 标题标签 <h1>至<h6>用于定义标题。<h1>是最大的标题&am…

模型部署——RKNN模型量化精度分析及混合量化提高精度

模型部署——RKNN模型量化精度分析及混合量化提高精度&#xff08;附代码&#xff09;-CSDN博客 3.1 量化精度分析流程 计算不同情况下&#xff0c;同一层网络输入值的余弦距离&#xff0c;来近似的查看每一层精度损失的情况。具体量化精度分析的流程如下&#xff1a; 3.2 量…

边缘检测-Tiny and Efficient Model for the Edge Detection Generalization

源代码: https://github.com/xavysp/TEED 论文地址&#xff1a;https://arxiv.org/pdf/2308.06468.pdf 大多数高级计算机视觉任务依赖于低级图像操作作为其初始过程。边缘检测、图像增强和超分辨率等操作为更高级的图像分析提供了基础。在这项工作中&#xff0c;我们考虑三个…

帮助读者掌握C语言编程基础知识的书籍

帮助读者掌握C语言编程的基础知识&#xff0c;了解如何将人工智能技术应用于自己的编程项目。 人工智能编程&#xff08;赋能C语言&#xff09; 作者&#xff1a; 黄箐、廖云燕、曾锦山、邢振昌 ISBN号&#xff1a; 9787302648796 出版日期&#xff1a; 2023-11-01 本书以C…

刷题DAY26 | LeetCode 39-组合总和 40-组合总和II 131-分割回文串

39 组合总和&#xff08;medium&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates…

小程序绕过 sign 签名

之前看到了一篇文章【小程序绕过sign签名思路】之前在做小程序渗透时也遇到了这种情况&#xff0c;但是直接放弃测试了&#xff0c;发现这种思路后&#xff0c;又遇到了这种情况&#xff0c;记录下过程。 并没有漏洞分享&#xff0c;仅仅是把小程序也分享出来&#xff0c;方便…

【以图搜图】GPUNPU适配万物识别模型和Milvus向量数据库

目录 以图搜图介绍项目地址Milvuscv_resnest101_general_recognition 代码使用流程结果展示模型部署环境Milvus部署及使用docker安装docker-compose安装Milvus可视化工具Attu进入网页端 Data数据示例点个赞再走呗&#xff01;比心&#x1f49e;️ 以图搜图 • &#x1f916; Mo…

Go微服务实战——服务的监控与链路追踪(监控数据可视化)

链路追踪背景 对于早期系统或者服务来说&#xff0c;开发人员一般通过打日志的方式来进行埋点&#xff08;常用的数据采集方式&#xff09;&#xff0c;然后再根据日志系统和性能监控定位及分析问题。对于单体的应用通过日志系统完全可以定位到问题&#xff0c;从而排查异常。…

Jpg图片怎么变成gif?三步在线转换gif动画

JPG是一种常见的图像格式&#xff0c;而GIF动态则是一种流行的动态图像格式。如果你想将多张JPG图片合成为一个GIF动画&#xff0c;下面是一些简单的方法来帮助你完成这个任务。通过使用Gif动画制作工具-GIF中文网&#xff0c;上传多张jpg格式图片轻松一键在线转换gif动画&…

Python爬虫获取接口数据

Python爬虫获取接口数据 正常人的操作​​​​​​​​​​爬虫的思路标题获取请求信息标题请求转换为代码完整代码请求返回信息执行程序获取静态网页数据的教程,适用于我们要爬取的数据在网页源代码中出现,但是还是有很多的数据是源代码中没有的,需要通过接口访问服务器来获…

Docker与containerd:容器技术的双璧

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker幻想曲&#xff1a;从零开始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Docker和containerd的背景…