关于Linux下程序报too many open file错误的排查总结

Linux下 too many open file错误排查总结

遇到的问题

本项目使用JAVA作为后台系统编程语言,使用tomcat作为中间件。遇到的问题是本系统在个别linux服务器上启动时报 too many open file错误。而且不管有问题还是没问题的这些Linux服务器安装的linux系统版本也是一模一样的,但同样的安装包启动后就会导致有个别几个报错。很是奇怪,所以有了一段艰难的排错过程。
首先是网上找有关too many open file的文章,发现有人说 使用 ulimit -n 可以查看当前系统允许的最大数量,我一查发现是1024,也就是系统默认的。但是我使用 lsof -p xxx | wc -l 命令查看java进程所占用的数量是4303,嗯,确实超过了1024,然后我找代码的原因。使用 lsof -p xxx > 1.txt,把文件占用的详细情况输出到文件中,发现文件中存在大量的 pipe/eventpoll(或inode)。然后初步怀疑是后台使用NIO导致的,于是我先注释掉了一些使用NIO作为服务的spring bean相关代码。再次启动服务 lsof -p xxx | wc -l 一看发现果然少了,由4303变为了3950。但是这一次系统正常启动了,没有报 too many open file错误。WTF?系统仍然还是1024的限制啊,为啥占用3950就可以了呢。接着找资料吧。。。后找到 open file 数量有soft 和hard之分 。再次使用命令 ulimit -Sn 得到1024,ulimit -Hn 得到4096

在这里插入图片描述
原来soft 和hard 搞的鬼,soft限制是软限制 ,是可以允许进程超过它的,但是不能高于hard。而/etc/security/limits.conf 文件中没有相关配置,所以soft默认是1024,hard模式是4096。so 4303 就报错 ,3950就没事。于是迅速修改了 /etc/security/limits.conf 中soft 跟hard的配置(双双改成了65535)。我又把注释掉spring bean放开,再次启动tomcat ,嗯,终于可以正常启动了,于是把修改方式告知现场工程师等待验证。2小时后,现场工程师打电话说还是启动服务还是报错啊,特么的什么情况,我赶紧检查下他是否修改正确,发现配置确实没问题,尴尬…。百思不得其解,到底是啥情况,什么鬼。
继续找资料,发现还存在 /etc/security/limits.d/ 这么一个目录,这个目录下可能会存在*-nproc.conf *-nofile.conf文件。如果存在后者,这个文件中的配置项会影响/etc/security/limits.conf中的配置。抱着试试的态度我看了下 /etc/security/limits.d/目录,发现服务器上只有
20-nproc.conf文件,并没有nofile.conf文件。难道又是没配置默认4096,于是我手动创建了此文件,把soft hard配置上。现场工程师再次测试,发现,(⊙o⊙)…,还是不行啊。
于是跟现场工程师沟通他是如何操作的,发现他的启动服务方式跟我自己测试的时候是不一样的,他是使用service方式来重启的 ,而我是直接使用tomcat启动脚本来启动的。难道是因为这个?但是service服务启动调用的也是tomcat 的启动脚本啊,不太可能是这个原因吧。抱着怀疑的态度继续找资料,果不其然,一篇资料上提到了 如果使用service自启动服务的话,它的文件描述符限制是单独控制的,不设置默认是4096。又是4096 ,程序占用的4303还是逃不过这个4096。修改这个数值需要在service文件的[Service]模块下添加该服务的单独配置LimitNOFILE=XXXX,于是又修改此项为65535。这一次直接使用service方式来启动检验下,终于好了!不管使用service启动还是tomcat脚本启动都没问题了。
以上就是排查此问题的全部过程,前前后后查资料 实际动手测试花费了3天时间。o(╥﹏╥)o

下面总结下,此次排查问题所学习到的一些命令。

相关的Linux命令

1.lsof -p pid | wc -l
查看某个pid进程所占用的文件描述符的总数

2.lsof|awk '{print $2}'|sort|uniq -c|sort -nr|more
显示所有进程所占用文件描述符的列表,以降序排列

3.lsof -p xxx > /home/1.txt
导出某个pid进程所占用的文件描述符详细情况到/home/1.txt 文件中

4.ulimit -n 等价于 ulimit -Sn
查看系统当前open file的soft 限制

5.ulimit -Hn
查看系统当前open file的hard 限制

6.ulimit -a
查看系统当前有关ulimit的所有配置参数

7.cat /proc/pid/limits
查看pid进程所限制的limit数量

遗留问题

目前只是解决了linux系统关于open file限制的问题。但是本系统在不同linux服务器上占用文件描述符大小不同的问题依旧存在。后边几天我又研究了下,因为我发现不同的服务器占用的文件描述符多的服务器它的CPU核数就高。这就很奇怪了,我开始怀疑到程序中哪块的代码会用到CPU核数了。后来发现后台使用了mina框架的SimpleIoProcessorPool类,跟踪这个类发现,这个类会初始化创建一个IoProcessor的数组用来处理IO请求,而数组的大小默认为服务器CPU内核数 + 1

/*     */ public class SimpleIoProcessorPool<S extends AbstractIoSession>
/*     */   implements IoProcessor<S>
/*     */ {
/*  79 */   private static final Logger LOGGER = LoggerFactory.getLogger(SimpleIoProcessorPool.class);
/*     */   
/*     */ 
/*  82 */   private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;

其中会初始化一个pool[]的数组,实例化很多IoProcessor对象

for (i = 1; i < this.pool.length; i++) {
/*     */         try {
/* 216 */           if (usesExecutorArg) {
/* 217 */             this.pool[i] = ((IoProcessor)processorConstructor.newInstance(new Object[] { this.executor }));
/*     */           } else {
/* 219 */             this.pool[i] = ((IoProcessor)processorConstructor.newInstance(new Object[0]));
/*     */           }
/*     */         }
/*     */         catch (Exception e) {}
/*     */       }

到此我严重怀疑就是这个东西导致的。因为现场的服务器CPU核数为144,也就是说初始化一次这个类默认就会初始化145个IoProcesser对象。

参考资料:
[1]: linux 文件句柄数查看命令.
[2]: Open Files – ulimit, lsof
[3]: Linux 文件句柄的这些技术内幕,只有 1% 的人知道
[4]: /etc/security/limits.conf 详解与配置
[5]: centos 7修改程序能打开的最大文件数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值