io_uring创建时返回-ENOMEM的原因及解决方案

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

io_uringLinux内核的高性能异步I/O接口。本文分析其创建时返回-ENOMEM的原因,并提供解决方案。

问题原因及解决方案

系统内存不足

问题原因分析

  • 系统物理内存不足时,内核将无法分配足够的内存来支持io_uring的初始化或运行。

  • 创建io_uring实例时,内核将尝试申请锁定内存页。即便系统总内存充足,但如果锁定内存(locked memory)上限配置过低,仍可能因无法满足内存锁定需求而返回 -ENOMEM 错误。

    执行以下命令,查看当前用户可使用的内存。

    ulimit -a

    结果如下图所示。

    image

    max locked memory代表该用户的最大锁定内存量。锁定内存代表标记为不可换出到磁盘的内存页,通常用于需要高性能和低延迟的应用场景。

解决方案

通过获得root权限执行目标程序,可以忽略lock_memory的内存限制。

  • 用户购买的ECS实例,可以使用sudo命令切换为root管理员权限执行目标程序。

  • 在容器场景中,需检查容器启动参数是否包含管理员权限。

    例如,在Docker容器内即使以root身份运行,仍可能报错。因为容器在启动时,未设置--privileged=true,导致容器内的root并不完全获得宿主机的root权限。

    警告

    设置--privileged=true参数将赋予容器几乎所有的主机权限,请谨慎设置。

io_uring队列参数设置过大

问题原因分析

io_uring 在初始化时需要分配内存以维护提交队列(SQ)和完成队列(CQ)。若队列深度(entries)设置过大,可能会超出系统的可用内存限制。

解决方案

根据实际需求合理设置 io_uring 的队列深度。

例如,避免设置过大的entries值。liburing中创建io_uring实例的接口有io_uring_queue_initio_uring_queue_init_params,调整参数entries使其不超过允许内存值。

int io_uring_queue_init(unsigned entries,
                       struct io_uring *ring,
                       unsigned flags)
int io_uring_queue_init_params(unsigned entries,
                              struct io_uring *ring,
                              struct io_uring_params *params);
说明

更多该函数接口的说明,请在安装liburing后使用man命令进行查询和阅读。

sudo yum install liburing -y
man io_uring_queue_init