原理
概念区分
内核维护的打开文件表(System Open File Table)
内核维护着一个打开文件表(看作一个数组),当某个进程打开一个文件时,内核会在这个表中添加一条记录,这个记录是一个结构体,包含了如下数据:文件的偏移量(进程操作(比如读)到文件的哪个位置)等等
一个进程可以打开同一个文件多次,那么就会内核的打开文件表中就会相应地增加多个记录。后文中我们把该表的记录叫做文件句柄
文件描述符(File Descriptor)
上面提到内核维护着一个打开文件表,其实进程也在PCB(Process Control Block)中维护着一个文件描述符表(File Descriptor Table)。当进程打开一个文件时,内核会在打开文件表中新增一条记录,同时进程也会在自已的文件描述符表中添加一条记录,该条记录中有一个指针,指向了内核的打开文件表中对应的记录。
一个进程可以打开同一个文件多次,那么就会在FDT中相应地增加多个记录。后文中我们将用打开文件数来表示进程的文件描述符的个数
Linux的参数调优
我们可能经常会遇到too many open files报错,这是因为“进程的打开文件数(文件描述符)过多,超过了进程的上限(一般都是进程的文件描述符超过限制,目前还没遇到文件句柄超出)”。所以,我们需要对进程的打开文件数上限做调整。
用户
如果没有对进程做显示的设置,进程的打开文件数上限会继承该进程所属的用户的打开文件数上限(正确的表述未找到,可以理解为该用户下单个进程的打开文件数上限)。
我们可以通过以下的方法设置用户的打开文件数上限
$ vim /etc/security/limits.conf
...
<user> - nofile 65535
...我们也可以通过* - nofile 65535来设置所有用户(*代表所有用户)的打开文件数上限。设置好之后我们可以通过命令ulimit -n来查看当前用户的打开文件数上限。
其实,打开文件数上限有分Soft Limit和Hard Limit。上面的设置方法中第二列为-,表示同时设置Soft Limit与Hard Limit。当然,我们也可以通过如下方法来设置用户的Soft Limit与Hard Limit,需要注意的是Soft Limit不能超过Hard Limit
命令ulimit -n查看的其实是Soft Limit。可以通过命令ulimit -Sn查看Soft Limit,通过命令ulimit -Hn查看Hard Limit。
系统的默认配置中,每个用户的Soft Limit为1024,Hard Limit为2048
Tips: 建议将用户的Soft Limit与Hard Limit设为一样,且所有用户都设大一些为65535
这样再说一点实用的小技巧,如果想查看其他用户的最大打开文件数,但是却不知道那个用户的密码。那么可以这样做:首先新建文件 ulimit.sh,内容如下
然后为ulimit.sh添加可执行属性,然后执行
进程
我们设置特定进程的打开文件数上限,但是注意进程的打开文件数不能超过用户的打开文件数。
对于systemd管理的进程,我们可以通过下面的方法同时设置Soft Limit与Hard Limit
可以通过cat /proc/<pid>/limits查看进程的打开文件数上限,如下Max open files一行
可以通过命令ls -l /proc/<pid>/fd | wc -l统计进程已经打开的文件数(文件描述符数)
Linux下的指标
/proc/sys/fs/file-max
该指标的官方定义为(官方链接待补充)
The value in file-max denotes the maximum number of file handles that the Linux kernel will allocate. When you get a lot of error messages about running out of file handles, you might want to raise this limit. The default value is 10% of RAM in kilobytes. To change it, just write the new number into the file
也就是说file-max指的是内核中文件句柄数的最大值
/proc/sys/fs/file-nr
其中最后一个参数就是file-max的值,第一个表示已经打开的文件句柄数,(第二个参数暂时还未清楚,好像一直为0)
/proc/<pid>/fd
该目录下有很多以数字命名的链接文件,这些数字,其实就是进程的文件描述符表中的索引,即数组的索引。所以经常也把文件描述符看成是一个数字。 进程每打开一个文件,文件描述符就会加1。这个目录下看到的文件描述符不一定连续,因为有些文件可能已经关闭了。
/proc/<pid>/limits
其中有一行叫Max open files,这里的open files其实就是进程的文件描述符的上限。不过注意有分Soft Limit和Hard Limit,我们可以为进程设置这两个值,但是Soft Limit必须小于等于Hard Limit(设置方法见《Nofile》)。如果没有给进程设置,则会继承该进程所属用户的配置。执行命令ulimit -Sn可以查看用户的Soft Limit,执行命令ulimit -Hn可以查看用户的Hard Limit
实践
接下来,我们写一个程序,打开一个文件一千次,然后查看内核的打开文件数与进程的文件描述符
执行前,我们先看一下内核的打开文件表,有6496个
然后运行该程序
接着,我们再来查看内核的打开文件表,为7488,约增加了1000个(因为有别的进程会打开或关闭文件)
我们查看该进程的id,为13196
然后查看进程的文件描述符,有1004个
其中0、1、2是每个进程都有的,代表stdin、stdout与stderr,我们来查看3,如下
Reference
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/tuning_and_optimizing_red_hat_enterprise_linux_for_oracle_9i_and_10g_databases/chap-oracle_9i_and_10g_tuning_guide-setting_file_handleshttps://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.genprogc/using_file_descriptors.htmhttp://www.opstool.com/article/166https://blog.csdn.net/lizhidefengzi/article/details/71481195
Last updated
Was this helpful?