Too many open files -- linux文件描述符的限制调整

时间:2022-08-29 04:04:06

        这两天做asterisk的性能测试,经常碰到这样的错误:“Too many open files”。

        我们知道,Linux下,文件描述符就是一个简单的整数值,习惯上,标准输入(standard input)的文件描述符是 0,标准输出(standard output)是 1,标准错误(standard error)是 2。POSIX 定义了STDIN_FILENO、STDOUT_FILENO 和STDERR_FILENO 来代替 0、1、2。这三个符号常量的定义位于头文件 unistd.h。

        文件描述符的有效范围是0 到OPEN_MAX。那么一个进程最多到底能打开多少个文件描述符呢?下面,就以asterisk进程为例来说明。


#ps –ef | grep asterisk

Too many open files -- linux文件描述符的限制调整

从第二列得到asterisk的PID为19488。

# cat /proc/19488/limits

Too many open files -- linux文件描述符的限制调整

        红线一行说明asterisk进程最大能打开1024个文件描述符(不包含它的子进程或创建出来的线程)。在/proc/19488/task/目录下,详细列出了其下的子任务的情况,每个子文件夹里同样有一个limits文件,限定了各子任务的情况。

 

         一个进程打开了几个文件描述符呢?

# ll /proc/19488/fd/

Too many open files -- linux文件描述符的限制调整

        子目录fd中,详细列出了进程打开的每个文件描述符,同样,/proc/19488/task/XXXX/fd下也会有子任务打开的文件描述符的情况。要知道有几个,执行

# ll /proc/19488/fd/ | wc -l

 

        怎样知道一个进程及其子进程和哪些文件有关联呢?lsof可以完成这工作。请注意,关联文件和打开文件描述符是两个不同的概念,关联文件的数量可能远远大于打开的文件描述符的数量。

# lsof | grep asterisk | wc –l

        也可以用父进程的PID过滤

# lsof | grep 19488 | wc –l

         我这里得到的值是9525

 

         怎样修改文件描述符的限定呢?临时修改,可以通过ulimit。

# ulimit -SHn 2048

 

          但是这样只能影响到当前的session,当终端重新连接或当前用户退出,配置就失效了。如果想永久变更需要编辑/etc/security/limits.conf 文件,添加如下两行:
* hard nofile 2048
* soft nofile 2048

 

         内核参数对文件描述符也有限制,如果设置的值大于内核的限制,也是不行的:

         查找file-max的内核参数:

# sysctl -a|grep file-max

        更改file-max的内核参数:

# sysctl -w file-max=65535

        Sysctl也是临时的,要想永久生效,可以通过更改sysctl的文件,编辑/etc/sysctl.conf文件,添加或修改以下一行:

fs.file-max=65535

 

        需要注意的是,文件描述符的限制,不局限于这里描述的这些,还可能和进程的启动参数、用户的环境设置有关。当然,如果是进程BUG造成文件描述符没有及时关闭回收,这增大限制也只是治标,根本上还得修复BUG。

       此外,lsof会列出系统中所占用的资源,但是这些资源不一定会占用打开的文件描述符(比如共享内存,信号量,消息队列,内存映射.等,虽然占用了这些资源,但不占用打开文件号),因此有可能出现cat /proc/sys/fs/file-max 的值小于lsof | wc -l。asterisk本身提供了一个启动脚本,名为safe_asterisk,脚本里面就对文件描述符做了一些设置。