dpdk secondary 进程 fd 不足问题分析
问题描述
产品业务环境中配置使用 2M 的大页,业务分配了大量的大页内存,某 dpdk secondary 进程运行过程中有如下日志信息:
EAL: rte_mem_virt2phy(): cannot open /proc/self/pagemap: Too many open files
EAL: rte_mem_virt2phy(): cannot open /proc/self/pagemap: Too many open files
EAL: rte_mem_virt2phy(): cannot open /proc/self/pagemap: Too many open files
信息收集
dpdk 版本
dpdk-19.11
ulimit 限制
查看到问题进程的 ulimit 限制为 1024
fd 被谁占用了?
大部分 fd 指向了 /dev/hugepages/xxx,需要进一步分析。
问题分析
dpdk 程序运行时,调用 dpdk 内部接口在大页上分配内存时,会在 /dev/huagepages 目录中创建内存映射文件供 dpdk 多进程共享。
当配置使用 2M 大页时,每 2M 大页内存需要在 /dev/hugepages 目录下创建一个 xxxmapxxx 文件,所有的 dpdk 进程在 eal 初始化过程中都会打开这些文件并做内存映射。当分配内存很大,ulimit 限制的最大打开 fd 数目过小时,程序就无法再打开新的文件。
解决方案
1. dpdk 程序启动时配置 ulimit 调大限制
缺点:
- 所有的 dpdk 进程都需要执行该操作
- ulimit 调整到的大小可能会随着大页内存占用的增加而调整
2. dpdk primary 进程启动时指定 --single-file-segments 参数
此参数配置 dpdk primary 进程将所有的大页映射到同一个文件,无论需要多大的大页内存都通过这一个文件进行映射,仅仅需要一个 fd。
实际测试效果如下:
[root@localhost] ls -lh /dev/hugepages/rtemap_0
-rw------- 1 root root 2.1G Mar 22 06:46 /dev/hugepages/rtemap_0
/dev/hugepages 目录下不会创建更多的文件来映射大页,当需要申请更多的大页内存时,仅调整单个文件的大小。
此方案从根本上解决了大页内存使用增加带来的 dpdk 程序 fd 占用增加问题,适用于打开的 fd 数目限制较少的场景,
single-file-segments 模式与默认实现的主要区别
阅读 dpdk 代码,确定 single-file-segments 模式与默认实现主要的区别在映射新大页的逻辑上,相关代码如下:
if (internal_config.single_file_segments) {
map_offset = seg_idx * alloc_sz;
ret = resize_hugefile(fd, map_offset, alloc_sz, true);
if (ret < 0)
goto resized;
fd_list[list_idx].count++;
} else {
map_offset = 0;
if (ftruncate(fd, alloc_sz) < 0) {
RTE_LOG(DEBUG, EAL, "%s(): ftruncate() failed: %s\n",
__func__, strerror(errno));
goto resized;
}
if (internal_config.hugepage_unlink &&
!internal_config.in_memory) {
if (unlink(path)) {
RTE_LOG(DEBUG, EAL, "%s(): unlink() failed: %s\n",
__func__, strerror(errno));
goto resized;
}
}
}
mmap_flags = MAP_SHARED | MAP_POPULATE | MAP_FIXED;
single-file-segments 需要 resize_hugefile,默认的实现仅需要按照固定大小 ftruncate 文件。
使用 single-file-segments 时,仅在单个文件上做 mmap,单个文件 mmap 的大小会随着使用的增加逐渐增大,可能是个问题。根据经验看,这部分并没有限制,取决于物理内存大小。
总结
dpdk 缺省以大页的单位做内存映射创建大页内存文件的方式会随着映射文件数目的增多,使用更多的 fd,当系统对 dpdk 进程的 open file max 限制很低时就容易出现 fd 不足的问题。
这时候使用 single-file-segments 参数能够很好地解决该问题,甚至于可以缺省配置该参数,从根源上解决此类问题。