Linux文件描述符与限制
文件描述符是什么?和文件句柄有啥区别?
文件描述符是linux/unix操作系统中特有的概念。相当于windows系统中的文件句柄。一个意思不同叫法。
Linux系统中, 每当进程打开一个文件时,系统就为其分配一个唯一的整型文件描述符,用来标识这个文件。标准C中每个进程默认打开的有三个文件,标准输入,标准输出,标准错误,分别用一个FILE结构的指针来表示,即stdin,stout,sterr,这三个结构分别对应着三个文件描述符0,1,2。
文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,依此类推。linux 操作系统通常对每个进程l能打开的文件数量有一个限制。
linux系统对文件描述符的限制
linux系统对文件描述符的限制有两个级别系统级别
使用cat /proc/sys/fs/file-max查看,默认值是根据内存大小,系统自动设置的,一般为内存大小(KB)的10%,shell下可以这样计算grep -r MemTotal /proc/meminfo | awk ‘{printf(“%d”,$2/10)}’(可能有各种其他原因导致file-max没有设置为内存的10%)1
2
3
4
5root@ubuntu:~# cat /proc/sys/fs/file-max
188273
root@ubuntu:~# grep -r MemTotal /proc/meminfo | awk '{printf("%d",$2/10)}'
183976
用户级别:默认是1024,使用ulimit -n查看1
2root@ubuntu:~# ulimit -n
1024
为什么要限制打开的文件描述符
资源问题:每个打开的文件都需要消耗内存来管理,而内存是有限的。
安全问题:如果不限制的话,有不怀好心的人启动一个进程来无限的创建和打开新的文件,会让服务器崩溃。
所以限制文件描述符的数量对于linux系统的稳定性是非常重要的。
配置文件
限制资源使用的配置文件/etc/security/limits.conf
/etc/security/limits.d/目录
/etc/security/limits.d/里面配置会覆盖/etc/security/limits.conf的配置
可以限制的资源类型如下所创建的内核文件的大小
进程数据块的大小
Shell 进程创建文件的大小
内存锁住的大小
常驻内存集的大小
打开文件描述符的数量
分配堆栈的最大大小
CPU 时间
单个用户的最大线程数
Shell 进程所能使用的最大虚拟内存
配置同时支持硬资源和软资源的限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18root@ubuntu:~# cat /etc/security/limits.conf
#
#
#* soft core 0
#root hard core 100000
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#ftp - chroot /ftp
#@student - maxlogins 4
* soft nofile 51200
* hard nofile 51200
#End of file
第一列表示用户和组(@开头)
第二列表示软限制还是硬限制
第三列表示限制的资源类型
第四列表示限制的最大值
hard和soft的区别: soft是一个警告值,而hard则是一个真正意义的阀值,超过就会报错,一般情况下都是设为同一个值。
core是内核文件,nofile是文件描述符,noproc是进程,一般情况下只限制文件描述符数和进程数就够了
系统级别查看
1
2root@ubuntu:~# cat /proc/sys/fs/file-max
183976
设置
临时性
1root@ubuntu:~# echo 1000000 > /proc/sys/fs/file-max
永久性
在/etc/sysctl.conf中设置,应该设什么值是最佳实践?比如8G的内存,设为8192/2 * 256 = 5242881fs.file-max = 1000000
用户级别
查看,-n默认查看的是soft limit,这个值是从/etc/security/limits.conf文件的* soft nofile 655350来的
1
2root@ubuntu:~# ulimit -n
170000
查看hard limit
1
2root@ubuntu:~# ulimit -Hn
170000
设置
临时性
通过ulimit -Sn设置最soft limit,注意soft limit必须小于hard limit1ulimit -Sn 160000
通过ulimit -Hn设置最Hard limit1ulimit -Hn 160000
同时设置soft limit和hard limit。对于非root用户只能设置比原来小的hard limit1ulimit -n 180000
永久性
root权限下,在/etc/security/limits.conf中添加如下两行,*表示所有用户,重启生效1
2* soft nofile 102400
* hard nofile 104800
注意:设置nofile的hard limit还有一点要注意的就是hard limit不能大于/proc/sys/fs/nr_open,假如hard limit大于nr_open,注销后将无法正常登录。
当前打开的文件描述符
查看系统当前打开的文件描述符数量
其中第一个数表示当前系统分配后已使用的文件描述符数,第二个数表示分配后未使用的(内核2.6版本中这个值总是为0,这并不是一个错误,它意味着已经分配的文件描述符总会被使用),第三个数等于最大值file-max。
1
2root@ubuntu:~# cat /proc/sys/fs/file-nr
2176 0 2048000
查看某个进程打开的文件描述符数量1
2root@ubuntu:~# ls /proc/35961/fd | wc -l
20
看下哪些进程占用的文件描述符比较多,排下序1
2
3
4
5
6
7
8root@ubuntu:~# sudo find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn
Count PID
129 1994
124 1993
122 1995
119 1992
118 23747
69 5504
错误的查看方法
使用lsof查看打开文件数是错误的sof的结果包含了并非以fd形式打开的文件,比如用mmap方式访问文件(FD一栏显示为mem),实际并不占用fd。
其中包括了像.so这样的文件。从结果看.jar文件也是以FD为mem和具体fd编号分别打开了一次。
CentOS 7的lsof(我这里lsof -v的版本号是4.87)是按PID/TID/file的组合对应一行,不是一行一个fd。同一个进程如果多个线程访问同一个文件通常只需要打开一次、占用一个fd,但在lsof中就显示多行。
如果用lsof -p ,则不按TID显示,结果数少很多。但仍包含了没有使用fd的文件。
正确的查看方法
查看/proc/中文件准确的查看fd使用总数的命令1cat /proc/sys/fs/file-nr
或者(结果多的时候运行需要一段时间)1sudo find /proc -print | grep -P '/proc/\d+/fd/'| wc -l
查看具体一个进程号的fd数量1ls -l /proc//fd | wc -l
查看哪个进程使用的fd最多,并排序1sudo find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn
但还要注意上面的命令返回的是系统的fd使用情况,而ulimit的配置是针对单用户的,两者是有区别的