← 返回内容列表

Linux io_uring 完全指南:下一代异步 I/O 模型

Linux io_uring 完全指南:下一代异步 I/O 模型

自 2002 年进入 Linux 内核以来,epoll 一直是异步 I/O 的事实标准。本文深入讲解 io_uring 的设计哲学、代码对比、高级特性及性能实测。

为什么 epoll 不够用了?

自 2002 年进入 Linux 内核以来,epoll 一直是异步 I/O 的事实标准。它的工作原理是就绪通知模型(readiness model):内核告诉用户态"这个文件描述符可以读了",然后应用程序自己调用 read() 或 write() 完成真正的 I/O。

这套机制在高并发场景下有一个根本性问题:每次 I/O 事件都要跨越用户态/内核态边界两次——一次 epoll_wait() 获取事件,一次 read()/write() 执行 I/O。当连接数达到万级,上下文切换的开销会严重拖累性能。

io_uring 的设计哲学

2019 年,Linux 5.1 引入了 io_uring,彻底改变了异步 I/O 的范式。它采用完成通知模型(completion model):用户态把 I/O 请求放入提交队列(Submission Queue,SQ),内核自行消费并执行;完成后将结果放入完成队列(Completion Queue,CQ)。两个队列都位于用户态与内核态共享的内存中,大多数情况下甚至不需要系统调用。

核心数据结构是一个环形缓冲区(ring buffer),这也是 "uring" 名字的由来。

零系统调用的稳态

通过 IORING_SETUP_SQPOLL 标志,可以让内核启动一个专用的轮询线程,持续监听 SQ。应用程序在 I/O 密集阶段完全不需要调用 io_uring_enter(),真正实现了"零系统调用"的稳态执行。

代码对比:epoll vs io_uring

下面是一段从标准输入读取数据的简单示例,分别用 epoll 和 io_uring 实现。

epoll 版本

int efd = epoll_create1(0);

struct epoll_event ev = {.events = EPOLLIN, .data.fd = STDIN_FILENO};

epoll_ctl(efd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);


struct epoll_event evs[10];

int n = epoll_wait(efd, evs, 10, -1); // 系统调用 1

char buf[4096];

int len = read(evs[0].data.fd, buf, sizeof(buf)); // 系统调用 2

// 每个 I/O 事件 = 2 次系统调用

io_uring 版本

struct io_uring ring;

io_uring_queue_init(32, &ring, 0);


// 获取 SQ 条目,填充读请求

struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);

io_uring_prep_read(sqe, STDIN_FILENO, buf, sizeof(buf), 0);

io_uring_sqe_set_data(sqe, buf);


// 一次提交即可,内核完成真正的 I/O

io_uring_submit(&ring);


// 等待完成

struct io_uring_cqe *cqe;

io_uring_wait_cqe(&ring, &cqe);

// I/O 结果已在 cqe->res 中,无需额外系统调用

高级特性

  • 零拷贝(Zero-copy):通过 io_uring_register_buffers() 提前注册缓冲区,内核无需每次 I/O 重新映射内存。对于网络发送,6.0+ 内核支持 IORING_OP_SEND_ZC,完全跳过内核缓冲区拷贝。
  • 链式操作(IOSQE_IO_LINK):将多个操作链接成一个原子序列,前一个完成后自动执行下一个,无需等待用户态确认。
  • 异步错误处理:错误码通过 CQE 的 res 字段异步返回,不阻塞提交队列。

性能实测与适用场景

在 TinyGate(一个反向代理教学项目)的基准测试中,从 epoll 迁移到 io_uring 后,每秒请求处理量(RPS)提升了约 3 倍,延迟 P99 下降了 40%。尤其在大量小包场景下,io_uring 的优势更加明显。

今天的建议很直接:只要内核版本 ≥ 5.1,新项目就应该首选 io_uring。epoll 只在没有 io_uring 支持的老旧系统上作为兼容性方案保留。

关联推荐: bixuebihui.com 上搜索"Linux 高性能编程"获取更多系统调优实战。

评论 (0)

加载评论中…