Linux 系统“Too many open files” ” 错误

Linux 系统“Too many open files” ” 错误

1 . 问题现象

这是一个基于 Java 的 Web 应用系统,在后台添加数据时提示无法添加,于是登录服务器查看 tomcat 日志,发现了如下异常信息:

java.io.IOException: Too many open files

通过这个错误,基本判断是系统可用的文件描述符不够了,由于 tomcat 服务是系统 www用户启动的,于是以 www 用户登录系统,通过“ulimit -n”命令查看系统可以打开最大文件描述符的数量,输出如下:

[www@tomcatserver ~]$ ulimit -n

65535

可以看到这个服务器设置的最大可打开的文件描述符已经是 65535 了,这么大的值应该够用了,但是为什么是提示这样的错误呢?

 

2 . 解决思路

这个案例涉及 Linux 下 ulimit 命令的使用,这里简单介绍下 ulimit 的作用和使用技巧。ulimit 主要是用来限制进程对资源的使用情况的,它支持各种类型的限制,常用的有:

  内核文件的大小限制

  进程数据块的大小限制

  Shell 进程创建文件大小限制

  可加锁内存大小限制

  常驻内存集的大小限制

  打开文件句柄数限制

  分配堆栈的最大大小限制

  CPU 占用时间限制用户最大可用的进程数限制

  Shell 进程所能使用的最大虚拟内存限制

ulimit 使用的基本格式为:

ulimit [options] [limit]

具体的 ulimit 参数(options) 含义如表所示。ulimit 参数的含义

 

参数      含义

-a         显示当前系统所有的 limit 资源信息

-H        设置硬资源限制,一旦设置不能增加

-S         设置软资源限制,设置后可以增加,但是不能超过硬资源设置

-c         最大的 core 文件的大小,以 blocks 为单位

-f         进程可以创建文件的最大值,以 blocks 为单位

-d         进程最大的数据段的大小,以 Kbytes 为单位

-m        最大内存大小,以 Kbytes 为单位

-n         可以打开的最大文件描述符的数量

-s         线程栈大小,以 Kbytes 为单位

-p         管道缓冲区的大小,以 Kbytes 为单位

-u         用户最大可用的进程数

-v         进程最大可用的虚拟内存,以 Kbytes 为单位

-t          最大 CPU 占用时间,以秒为单位

-l          最大可加锁内存大小,以 Kbytes 为单位

 

在使用 ulimit 时,有以下几种使用方法:

(1)在用户环境变量中加入

如果用户使用的是 bash,那么就可以在用户目录的环境变量文件.bashrc 或.bash_profile中加入“ulimit -u 128”来限制用户最多可以使用 128 个进程。

(2)在应用程序的启动脚本中加入

如果应用程序是 tomcat,那么就可以在 tomcat 的启动脚本 startup.sh 中加入“ulimit -n 65535”来限制用户最多可以使用 65535 个文件描述符。

(3)直接在 shell 命令终端执行 ulimit 命令

这种方法的资源限制仅仅在执行命令的终端生效,在退出或关闭终端后,设置失效,并且这个设置不影响其它 shell 终端。

有时候为了方便起见,也可以将用户资源的限制统一由一个文件来配置,这个文件就是/etc/security/limits.conf,该文件不但能对指定用户的资源进行限制,还能对指定组的资源进行限制。该文件的使用规则如下:

<domain> <type> <item> <value>

其中:

  domain 表示用户或组的名字,还可以使用 * 作为通配符,表示任何用户或用户组。

  type 表示限制的类型,可以有两个值,soft 和 hard,分别表示软、硬资源限制。

  item 表示需要限定的资源名称,常用的有 nofile、cpu、stack 等。分别表示最大打

开句柄数、占用的 cpu 时间、最大的堆栈大小。

  value 表示限制各种资源的具体数值。

除了 limits.conf 文件之外,还有一个/etc/security/limits.d 目录,可以将资源限制创建一个文件放到这个目录中,默认系统会首先去读取这个目录下的所有文件,然后才去读取limits.conf 文件。在所有资源限制设置完成后,退出 shell 终端,再次登录 shell 终端后,ulimit设置即可自动生效。

 

3 . 解决问题

在介绍了 ulimit 知识后,接着上面的案例,既然 ulimit 设置没问题,那么一定是设置没有生效导致的。接下来检查下启动 tomcat 的 www 用户环境变量下是否添加了 ulimit 限制,检查后发现,www 用户下并无 ulimit 资源限制,于是继续检查 tomcat 启动脚本 startup.sh 文件,是否添加了 ulimit 限制,检查后发现也并无添加,最后考虑是否将限制加到了 limits.conf

文件中,于是检查 limits.conf 文件,操作如下:

[root@tomcatserver ~]# cat /etc/security/limits.conf|grep www

www soft nofile 65535

www hard nofile 65535

从输出可知,ulimit 限制加在了 limits.conf 文件中,既然限制已经加了,配置也没有错,为何还会报错呢?经过长时间思考,判断只有一种可能,那就是tomcat的启动时间早于ulimit资源限制的添加时间,于是首先查看下 tomcat 的启动时间,操作如下:

[root@tomcatserver ~]# more /etc/issue

CentOS release 6.3 (Final)

Kernel \r on an \m

[root@tomcatserver ~]# uptime

15:10:19 up 283 days, 5:37, 4 users, load average: 1.20, 1.41, 1.35

[root@tomcatserver ~]# pgrep –f tomcat

4667

[root@tomcatserver ~]# ps -eo pid,lstart,etime|grep 4667

4667 Sat Jul 6 09:33:39 2019 77-05:26:02

从输出看,这台服务器已经有 283 天没有重启过了,而 tomcat 是在 2019 年 7 月 6 日 9

点多启动的,启动了近 77 天零五个半小时了,接着继续看看 limits.conf 文件的修改时间,

操作如图所示,查看 limits.conf 文件的最后修改时间。

通过 stat 命令可以很清楚地看出,limits.conf 文件最后的修改时间是 2013-07-12,通过

查问相关的 Linux 系统管理人员,基本确认就是在这个时候添加的 ulimit 资源限制,这样此

案例的问题就很明确了。由于 ulimit 限制的添加时间晚于 tomcat 最后一次的启动时间,而

在此期间内,tomcat 服务一直未重启过,操作系统也一直未重启过,那么 ulimit 资源限制对

于 tomcat 来说始终是不生效的,同时,由于此操作系统是 Centos6.3,系统默认的最大可用

句柄数是 1024,java 进程还是用的 Linux 默认的这个值,因此出现“Too many open files”

的错误也是合乎情理的。

问题清楚之后,解决问题的方法非常简单,重启 tomcat 服务即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深海天哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值