zoukankan      html  css  js  c++  java
  • 运维实战案例之“Too many open files”错误与解决方法

    运维实战案例之“Too many open files”错误与解决方法

     
    技术小甜 2017-11-16 15:02:00 浏览869
     

    一、问题现象

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

    java.io.IOException: Too many open files

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

    [www@tomcatserver ~]$ ulimit  -n

    65535

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

    二、解决思路

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

    内核文件的大小限制

    进程数据块的大小限制

    Shell进程创建文件大小限制

    可加锁内存大小限制

    常驻内存集的大小限制

    打开文件句柄数限制

    分配堆栈的最大大小限制

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

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

    ulimit使用的基本格式为:

    ulimit [options] [limit]

    具体的options参数含义如下表所示:

    选项 含义

    -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设置即可自动生效。

    三、解决问题

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

    1
    2
    3
    [root@tomcatserver ~]# cat /etc/security/limits.conf|grep www
    www soft nofile 65535
    www hard nofile 65535

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@tomcatserver ~]# more /etc/issue
    CentOS release 6.3 (Final)
    Kernel   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 2013 77-05:26:02

    从输出看,这台服务器已经有283天没有重启过了,而tomcat是在2013年7月6号9点多启动的,启动了近77天零五个半小时了,接着继续看看limits.conf文件的修改时间,操作如下图所示:

    wKiom1OxIoXAY-q6AADyDaNe9Vs461.jpg

    通过stat命令可以很清楚的看出,limits.conf文件最后的修改时间是2013-07-12,通过查问相关的Linux系统管理人员,他们基本确认就是在这个时候添加的ulimit资源限制,这样此案例的问题就很明确了。由于ulimit限制的添加时间晚于tomcat最后一次的启动时间,而在此期间内,tomcat服务一直未重启过,操作系统也一直未重启过,那么ulimit资源限制对于tomcat来说始终是不生效的,同时,由于此操作系统是Centos6.3,系统默认的最大可用句柄数是1024,那么java进程还是用的Linux默认的这个值,出现“Too many open files”的错误,也是合乎情理的。

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

  • 相关阅读:
    Android之文件&XML
    Dialog组件
    Android模拟器使用SD卡(2)
    Android 蓝牙开发浅析
    创建和解析XML
    android 读取文件相关
    android 网络编程 HttpGet类和HttpPost类使用详解
    Android模拟器使用SD卡(1)
    Android中控件的OnKeyListener()事件
    [转]Android蓝牙开发浅谈
  • 原文地址:https://www.cnblogs.com/xuanbjut/p/11652928.html
Copyright © 2011-2022 走看看