tomcat环境下服务器文件句柄耗尽(Too Many Open Files)的问题排查

前段时间帮助公司解决了一次tomcat环境服务器的异常,今天有时间过来总结一下。

 

问题的表现:

tomcat服务在重启之后,短时间内会承受大量访问,由于这个时候缓存还没建立,每次访问都将消耗一定资源(数据库连接或者文件IO),并发量在2000左右的时候tomcat服务开始抛出大量Too Many Open Files的异常,主要是文件IO一块的异常,数据库连接池配置恰当就不会抛异常。

 

问题分析:

这是一个典型的文件句柄耗尽的异常,在linux里头“一切皆文件”,所以虽然提示“文件”打开太多,其实也有可能是socket打开太多或者设备打开太多。

 

文件句柄是用来干嘛的?


句柄当做一个人的名字,并"可以通过名字(句柄),实现对句子的引用和访问",感觉这种比喻好象贴近,但问题是可能有许多人叫同一个名字,但句柄所以有意义正因为它具有唯一性,所以这种比喻也有问题,如果换个说法,说句柄是表示你的进程与外界的i/o连接,把它当作是一个连接的名字是不是更恰当些? 文件句柄是一个十六位长度的二进制代码(Windows95后为32位无符号整数),代表一个已被打开文件的通道号,借助于这个句柄,你的应用程序即可使用这个相应的句柄对文件进行随意存取操作,说白了文件句柄其实是一串代表着特殊含义的号码; 当然其实系统是用句柄与一些资源联系起来的,当由系统管理,动态分配给你应用程序的某些资源的代号,你就可以使用句柄访问相应的资源了,尤其在Windows系统中,有很多东东都使用句柄,如窗口,socket。


简单看来程序通过句柄获得资源的引用,来进行资源的打开和关闭的操作。

 

为什么会出现文件句柄耗尽的情况?

 

主要是因为linux在文件句柄的数目上有两个级别的限制。一个是系统级别的总数限制,一个是针对用户的限制。默认情况下每个用户所能使用的句柄数是1024。一般情况下1024也够用了,但是在大容量的系统上,特别是会频繁使用网络通信和文件IO的系统上,1024很快就被耗光了。所以首先我们要调整这个值。修改方法如下:


1. ulimit -a 查看当前用户的文件句柄限制  
2. 用户级别的句柄数限制修改。  
修改 /etc/security/limits.conf 增加下面的代码:  
用户名(或者用*表示所有用户)  soft nofile 65535    
用户名 hard nofile 65535   
有两种限制,一种是soft软限制,在数目超过软限制的时候系统会给出warning警告,但是达到hard硬限制的时候系统将拒绝或者异常了。  
修改之后可能需要重启shell生效。  
3. 系统级别的句柄数限制修改。  
sysctl -w fs.file-max 65536  
或者  
echo "65536" > /proc/sys/fs/file-max  
两者作用是相同的,前者改内核参数,后者直接作用于内核参数在虚拟文件系统(procfs, psuedo file system)上对应的文件而已。  
可以用下面的命令查看新的限制  
sysctl -a | grep fs.file-max  
或者  
cat /proc/sys/fs/file-max  
修改内核参数  
/etc/sysctl.conf  
echo "fs.file-max=65536" >> /etc/sysctl.conf  
sysctl -p  
查看系统总限制 命令:cat /proc/sys/fs/file-max    
查看整个系统目前使用的文件句柄数量命令:cat /proc/sys/fs/file-nr   
查看某个进程开了哪些句柄 :lsof -p pid    
某个进程开了几个句柄 :lsof -p pid |wc -l    
也可以看到某个目录 /文件被什么进程占用了,显示已打开该目录或文件的所有进程信息 :lsof path/filename 

具体这个值应该设置成多少?

优先级(Open File Descriptors):
soft limit < hard limit < kernel < 实现最大file descriptor数采用的数据结构所导致的限制

 

其实这个值倒是没有具体限制,但是分配的值如果太大反而会影响系统性能,所以要根据具体应用调配权衡。

 

问题的解决方案:

首先当然是修改linux句柄数限制到一个合适的值。

然后就是应用本身的一个调整。有这么几种情况:

1.数据库连接池的优化。必须要使用连接池,否则句柄没耗光数据库就崩了。。。

2.抓取资源的时候有可能会用到HttpClient,尽量也应该使用连接池来控制连接数。

关于HttpClient的连接池配置可以查看我另外一文:http://blog.csdn.net/shootyou/archive/2011/05/12/6415248.aspx

3.连接池设置的把握,建立连接超时时间,读取超时时间,连接数目,等待时间,等都需要配置到一个合适的值,否则发挥不出连接池的性能。

 

 2015-05-12更新:

    Caused by: java.lang.OutOfMemoryError: unable to create new native thread   
如果遇到类似这样的问题,是进程数达到所能创建的上线了。nproc是单独控制进程数的。而linux下的线程是使用了轻量级线程LWP技术,实际上是会占用系统进程数限制。

具体可以参考:http://www.dbi-services.com/index.php/blog/entry/linux-how-to-monitor-the-nproc-limit-1




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值