记一次由nproc引起的Tomcat OutOfMemory故障

最近有一个应用新上生产环境,我对系统人员的部署建议是每台4C8G的虚拟机部署2个Tomcat实例,总共部署20个节点。结果他们觉得这样虚拟机个数太多管理不方便,就将虚拟机的配置改成8C16G,每个虚拟机部署5个Tomcat实例。表面上来看问题不大,无非就是把多个鸡蛋放在同一个篮子了而已,在没有出现大问题之前我也找不到好的理由来反驳他们。

应用上线运行了几天,刚开始几天没什么问题。大约过了一个礼拜左右,每天就会出现其中一台虚拟机上5个Tomcat实例同时挂掉。查看错误日志,每个Tomcat都是因为”OutofMemory: cannot create a thread”而停止响应,从监控来看,每个Tomcat在当时的总线程数都是210左右。进过分析dump日志,发现这个并不是因为JVM的堆内存不足引起,也不是因为操作系统的内存不足引起的。我猜测是因为文件描述符的限制了。经查看,原来系统室提供的虚拟机是根据总行的要求,将ulimit的nofile设置成了4096,将fs.file-max也设置成了4096.遂让他们把这两个参数逐个调大到65535。原本以为问题就此解决了,不想第二天当高流量来了的时候,还是会出现同样的症状。当时就没思路了,然后重新撸了一遍所有的参数,Tomcat的Connector最大线程数(maxActive)设置都是500,文件描述符远远足够,只是知道是操作系统限制了Tomcat来创建更多的线程,但不知道到底是什么参数来限制的。

通过进一步分析JVM的dump文件,有一个参数引起了我的注意,nproc=1024,1024/5=205, 这个数量级刚好跟我们的监控数据(Tomcat crash的时候)接近。难道是因为这个参数的限制?但在我的知识体系里面,nproc一直都是用来限制进程数的,通过“man ulimit”来查看得到解释是“The maximum number of processes available to a single user”。而现在是线程数(The maximum number of Thread)被限制了,process和thread是两个完全不同级别的限制啊,到底是怎么回事呢?

这个时候,还是google解救了我。我怀着这个猜测在google上直接搜索了“Linux nproc”,没想到立即就找到IBM官方的一篇文章,“Insufficient ulimit -u (NPROC) Value Contributes to Native OutOfMemory”, 里面有一个句很关键的解释让我茅塞顿开:

“The nproc limit on Linux counts the number of threads within all processes that can exist for a given user.”

原来如此,看来问题的症结就在这里了,nproc表面上来看限制的是进程总数,其实是连线程总数一起限制的。再进一步研究发现,早期的Linux是没有“线程(Thread)”这个概念的,直到Linux 2.6内核出来引入NPTL – Native POSIX Thread Library的方案,才有了大家通普遍理解的线程的实现。但是和Windows平台不同的是,Linux里面的线程其实是通过fork函数来fork一个子进程的方式来实现的,并且是通过关闭COW – Copy on Write特性来实现线程间独立但是又共享父进程内存的效果。总而言之,在Linux世界里,线程其实就是进程,进程是Linux内核调度的实体,nproc是为了限制内核”可调度实体”的总数的,所以就一并将线程也限制进去了。这与Windows世界“线程是任务的调度实体”哲学大部相同。

在调整nproc参数的时候,还有一个小细节需要注意。在/etc/security/limits.d/下面有一个90-nproc.conf文件,里面配置了系统默认nproc值:” * soft nproc 1024″,这个文件里面的配置会覆盖/etc/security/limits.conf里面相同的配置项。正因为如此,当我们的系统人员在limits.conf末尾加上”* soft nproc 102400″以后,意图粗暴的将所有用户的nproc值调大,但是重启Tomcat以后,但是在/proc/<tomcat_pid>/limits文件中看到的nproc限制还是1024. 后来把”*”号改成tomcat用户以后才真正生效。

将所有虚拟机的这个参数调整好以后,Tomcat的OutofMemory的问题就彻底消失了。

发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>