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 库,核心流程是 "初始化队列→提交请求→等待完成→处理结果"。

相关推荐
优雅的38度2 小时前
linux环境下,使用docker安装apache kafka (docker-compose)
linux·架构
想唱rap2 小时前
表的约束条件
linux·数据库·mysql·ubuntu·bash
山上三树3 小时前
对比用户态线程与内核态轻量级进程
linux
2501_948195343 小时前
RN for OpenHarmony英雄联盟助手App实战:设置实现
linux·ubuntu
阿甘正赚.3 小时前
Linux初学
linux·运维·服务器
物随心转3 小时前
线程阻塞调用与同步调用的区别
linux
虚神界熊孩儿3 小时前
Linux下修改docker和harbor默认网段的方法
linux·docker·harbor
Jay Chou why did3 小时前
ARM寄存器
linux
乌日尼乐3 小时前
【Linux】iptables使用详解(RT)
linux