上海好的网站有哪些,wap网站 视频教程,莱芜金点子2023最新招聘,在线教育网站开发时长说到高性能网络编程#xff0c;我们第一时间想到的是epoll机制#xff0c;epoll很长一段时间统治着整个网络编程江湖#xff0c;然而io_uring的出现#xff0c;似乎在撼动epoll的统治地位#xff0c;今天我们来揭开io_uring的神秘面纱。
1.io_uring简介
io_uring是一个L…说到高性能网络编程我们第一时间想到的是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请求结果。 SQSubmission Queue提交队列用于存储SQE的数组。 CQCompletion Queue完成队列用于存储CQE的数组。 SQ RingSQ环形缓冲区包含SQ头部索引head尾部索引tail队列大小等信息。 CQ RingCQ环形缓冲区包含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 工作流程 创建io_uring对象首先需要创建一个io_uring对象可以使用io_uring_setup()函数来完成。 准备I/O请求在进行I/O操作之前需要准备相关的I/O请求。可以使用io_uring_prep_XXX()系列函数来准备不同类型的I/O请求例如io_uring_prep_read()用于读取数据io_uring_prep_write()用于写入数据。 提交I/O请求准备好I/O请求后可以使用io_uring_submit()函数将请求提交给内核内核会将这些请求放入一个队列中等待执行。 等待IO请求完成可以使用io_uring_wait_cqe()函数来等待I/O请求的完成一旦请求完成内核会将完成事件放入一个完成队列中。 获取IO请求结果可以使用io_uring_peek_cqe()函数来获取完成队列中的完成事件。然后可以通过事件的信息来处理完成的I/O请求例如读取数据或者处理错误。 释放IO请求结果获取完IO请求结果使用io_uring_cqe_seen()函数来释放IO请求结果以便内核可以继续使用。 重复执行可以重复执行上述步骤以处理更多的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对象创建一个新的filefile private_data成员指向io_ring对象申请一个未使用的文件描述符fdfd映射至file并存储在进程已打开文件表中。
注意mmap内存映射需要用到该fd。
相关视频推荐
linux c/c开发之高性能网络编程面试与开发都非常重要的技术不容错过tcp/ip、udp、epoll、网络io、reactor、网络协议栈https://www.bilibili.com/video/BV1Ru4y1J7E3/
Linux C/C开发后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全
需要C/C Linux服务器架构师学习资料加qun812855908获取资料包括C/CLinuxgolang技术NginxZeroMQMySQLRedisfastdfsMongoDBZK流媒体CDNP2PK8SDockerTCP/IP协程DPDKffmpeg等免费分享 3.3 io_uring对象内存映射 通过io_uring_setup系统调用创建完io_uring对象后用户程序还不能直接访问io_uring对象此时用户程序需要通过mmap函数将io_uring对象SQCQ以及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数组而是需要通过headmask和tail mask操作指向SQ数组mask数组为数组长度减1因为数组有固定大小所以需要通过mask方式防止越界访问数组这种方式可以让数组形成一个环形缓冲区。
3.5 等待IO请求完成 IO请求的处理有两种方式 方式1SQ线程从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值得多花点时间研究