io_submit 返回 eagain 的根本原因是内核 aio 上下文资源耗尽:/proc/sys/fs/aio-nr 接近或等于 /proc/sys/fs/aio-max-nr,表明系统级异步 i/o 事件池已满,新请求无法提交。

io_submit 返回 EAGAIN 的根本原因
不是代码写错了,也不是磁盘坏了,而是内核 AIO 上下文资源耗尽了。io_submit 本质是向内核提交异步 I/O 请求,它依赖一个叫 aio_context_t 的上下文结构,而每个上下文能承载的未完成请求(io_event)数量受系统全局限制。当 io_setup() 创建上下文后,后续 io_submit() 调用若发现当前上下文已满、或系统级 AIO 资源池被占光,就会直接返回 -1 并置 errno = EAGAIN。
确认是不是 AIO 资源不足
别猜,直接查两个关键数字:
-
cat /proc/sys/fs/aio-nr:当前所有进程已占用的 AIO 事件数 -
cat /proc/sys/fs/aio-max-nr:系统允许的最大值(默认通常为 65536)
如果 aio-nr 接近甚至等于 aio-max-nr,基本就是它了。注意:这个计数包含所有进程——MySQL 8.4、PostgreSQL、自研 AIO 网络库、甚至某些日志框架都可能悄悄创建 AIO 上下文。
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
临时绕过和长期修复怎么选
临时手段只适用于调试或紧急止血;长期方案必须从应用层收敛 AIO 使用:
- 临时调高上限:
echo 1048576 > /proc/sys/fs/aio-max-nr(重启失效) - 永久生效:往
/etc/sysctl.conf加fs.aio-max-nr = 1048576,再运行sysctl -p - 更推荐的做法:检查你的程序是否重复调用
io_setup却没配对io_destroy;或者是否在连接池里为每个 socket 都建独立 AIO 上下文——这属于典型资源滥用 - MySQL 场景下可关掉 AIO:
innodb_use_native_aio = OFF(但会损失部分吞吐,仅限权衡后启用)
为什么 epoll + 非阻塞 socket 比 AIO 更稳
这不是性能高低的问题,而是工程鲁棒性的差异:
- AIO 依赖内核态资源池,且错误反馈滞后(
io_submit成功不代表执行成功,得等io_getevents才知道失败) - epoll + 非阻塞 socket 把控制权完全留在用户态:
send返回EAGAIN时你知道缓冲区满,立刻epoll_ctl(EPOLL_CTL_MOD)关注EPOLLOUT,等可写再发——路径清晰、状态可测、无隐式资源竞争 - 很多所谓“AIO 高性能”场景,实际是用错了:小包高频写、连接数远大于并发请求数时,AIO 反而因上下文管理开销和锁争用拖慢整体
真正容易被忽略的是:AIO 错误不报错,它就静默失败——io_submit 返回 -1 且 errno == EAGAIN 时,如果你没检查 errno 就继续往下走,后续 io_getevents 可能永远收不到对应 event,请求就此丢失。










