Linux io_uring:高性能异步I/O革命

io_uring 是 Linux 5.1 内核正式引入的新一代异步 I/O 接口,由 Jens Axboe 开发(也是 libaio、block/io 子系统维护者),目的是解决传统异步 I/O(如 libaio)的局限性,提供更高效、更易用、更低开销的异步 I/O 能力。

简单来说:

  • 传统同步 I/O 会阻塞线程,而异步 I/O 让线程发起 I/O 请求后可以继续做其他事,等 I/O 完成后再处理结果;
  • io_uring 相比老的异步 I/O 方案,核心是通过共享环形队列(Ring Buffer) 实现用户态与内核态的通信,大幅减少系统调用次数和内存拷贝开销。

一、核心设计与优势

  1. 核心组件(三个关键环形队列)

io_uring 的核心是用户态和内核态共享的 3 个环形队列(内存映射,无需拷贝):

  • 提交队列(Submission Queue, SQ):用户态向这里提交 I/O 请求(如读文件、写文件);

  • 完成队列(Completion Queue, CQ):内核处理完 I/O 请求后,将结果(成功 / 失败、字节数等)放入这里,供用户态读取;

  • 提交队列门(SQ Ring Tail):用户态通过更新这个指针,告诉内核 "有新请求要处理"(替代传统的系统调用)。

  1. 核心优势
对比维度 传统异步 I/O (libaio) io_uring
系统调用次数 每次请求都要调用 批量提交 / 获取,大幅减少
支持的操作 仅支持块设备 / 文件 支持文件、网络、管道等
易用性 接口复杂,易出错 接口更简洁,支持同步 / 异步
性能 开销高 极低的上下文切换开销
功能完整性 无超时、取消等功能 支持超时、取消、链接请求

二、基本使用流程(C 语言示例)

io_uring 通常结合 liburing 库(用户态封装库)使用,先安装依赖:

bash 复制代码
# 安装 liburing 开发包(以 Ubuntu 为例)
sudo apt install liburing-dev

以下是一个简单的 "异步读文件" 示例,核心步骤清晰:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <liburing.h>

#define BUF_SIZE 4096
#define QUEUE_DEPTH 16  // 队列深度(最多同时处理的请求数)

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "用法: %s <文件名>\n", argv[0]);
        return 1;
    }

    // 1. 初始化 io_uring 实例
    struct io_uring ring;
    int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
    if (ret < 0) {
        perror("io_uring_queue_init 失败");
        return 1;
    }

    // 2. 打开文件(只读)
    int fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("open 失败");
        io_uring_queue_exit(&ring);
        return 1;
    }

    // 3. 分配缓冲区
    char *buf = malloc(BUF_SIZE);
    if (!buf) {
        perror("malloc 失败");
        close(fd);
        io_uring_queue_exit(&ring);
        return 1;
    }

    // 4. 获取提交队列项(SQE)
    struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
    if (!sqe) {
        perror("io_uring_get_sqe 失败");
        free(buf);
        close(fd);
        io_uring_queue_exit(&ring);
        return 1;
    }

    // 5. 填充读请求(异步读文件)
    io_uring_prep_read(sqe, fd, buf, BUF_SIZE, 0);  // 0 是文件偏移量
    io_uring_sqe_set_data(sqe, buf);  // 关联缓冲区,方便后续获取

    // 6. 提交请求到内核
    ret = io_uring_submit(&ring);
    if (ret < 0) {
        perror("io_uring_submit 失败");
        free(buf);
        close(fd);
        io_uring_queue_exit(&ring);
        return 1;
    }

    // 7. 等待并获取完成结果(CQE)
    struct io_uring_cqe *cqe;
    ret = io_uring_wait_cqe(&ring, &cqe);
    if (ret < 0) {
        perror("io_uring_wait_cqe 失败");
        free(buf);
        close(fd);
        io_uring_queue_exit(&ring);
        return 1;
    }

    // 8. 处理结果
    if (cqe->res < 0) {
        fprintf(stderr, "读文件失败: %d\n", cqe->res);
    } else {
        printf("成功读取 %d 字节,内容前 100 字节:\n", cqe->res);
        fwrite(buf, 1, (cqe->res > 100 ? 100 : cqe->res), stdout);
        printf("\n");
    }

    // 9. 标记 CQE 已处理
    io_uring_cqe_seen(&ring, cqe);

    // 10. 清理资源
    free(buf);
    close(fd);
    io_uring_queue_exit(&ring);

    return 0;
}

编译运行:

bash 复制代码
gcc -o io_uring_demo io_uring_demo.c -luring
./io_uring_demo test.txt  # test.txt 是你要读取的文件

代码关键部分解释

  • io_uring_queue_init:初始化 io_uring 实例,指定队列深度;

  • io_uring_get_sqe:从提交队列中获取一个空的请求项;

  • io_uring_prep_read:填充读请求(还支持 io_uring_prep_write/io_uring_prep_accept 等);

  • io_uring_submit:将请求提交到内核;

  • io_uring_wait_cqe:阻塞等待请求完成(也可以非阻塞轮询);

  • io_uring_cqe_seen:告诉内核该完成项已处理,可复用。

三、适用场景

io_uring 主要用于高并发、高吞吐的 I/O 密集型场景:

  1. 高性能服务器(如 Nginx 已引入 io_uring 支持);

  2. 数据库存储引擎(如 PostgreSQL、MySQL);

  3. 文件传输工具(如 fio 压测工具、rsync);

  4. 云原生组件(如容器运行时、存储网关)。

四、总结

  1. io_uring 是 Linux 内核新一代异步 I/O 接口,核心是通过共享环形队列减少用户态 - 内核态交互开销;

  2. 相比传统异步 I/O,它支持更多操作类型、更易用、性能更高;

  3. 使用时通常结合 liburing 库,核心流程是 "初始化队列→提交请求→等待完成→处理结果"。

相关推荐
getapi16 分钟前
注塑件的费用构成
linux·服务器·ubuntu
郝学胜-神的一滴1 小时前
深入解析C/S模型下的TCP通信流程:从握手到挥手的技术之旅
linux·服务器·c语言·网络·网络协议·tcp/ip
释怀不想释怀1 小时前
Linux网络基础(ip,域名)
linux·网络·tcp/ip
初願致夕霞1 小时前
Linux_进程
linux·c++
开开心心就好1 小时前
AI人声伴奏分离工具,离线提取伴奏K歌用
java·linux·开发语言·网络·人工智能·电脑·blender
lucky-billy1 小时前
Ubuntu 下一键部署 ROS2
linux·ubuntu·ros2
Thera7772 小时前
【Linux C++】彻底解决僵尸进程:waitpid(WNOHANG) 与 SA_NOCLDWAIT
linux·服务器·c++
阿梦Anmory2 小时前
Ubuntu配置代理最详细教程
linux·运维·ubuntu
云姜.2 小时前
线程和进程的关系
java·linux·jvm
小Tomkk2 小时前
数据库 变更和版本控制管理工具 --Bytebase 安装部署(linux 安装篇)
linux·运维·数据库·ci/cd·bytebase