进程数限制导致的线上问题

先来了解下Linux系统的最大线程数限制的参数有哪些:

  • /proc/sys/kernel/threads-max:内核所能使用的线程的最大数目,由物理内存决定,32G内存的默认值为255928。
  • /proc/sys/vm/max_map_count:限制一个进程可以拥有的VMA(虚拟内存区域)的数量,默认值为65530。
  • ulimit -u:单个用户允许的最大进程或线程上限,默认root用户不限制,其他用户为4096。
  • /proc/sys/kernel/pid_max:操作系统线程数限制。为了兼容旧版(旧版本32位操作系统的最大值为32768),默认为32768。PS:其实64位操作系统最多可以设置为2^22,400多万。

问题出现前这些参数的实际值

在问题出现之前,ulimit -u的已经调整到了404800,其他的都为默认值。

问题描述

xshell连接服务器时报错:fork:cannot allocate memory

解决过程

其实这个报错直接就可以定位到是pid_max的问题。

查询当前整个系统已用的线程或进程数:

$ pstree -p | wc -l
32602

###这是问题解决之后查的,问题产生时的值应该比32768略小些。

问题已经很明确了,就是pid_max的值不够大造成的。

知道了问题,那就好办了,直接修改/proc/sys/kernel/pid_max的值:

#临时生效
$ echo 1000000 > /proc/sys/kernel/pid_max

#永久生效
$ echo "kernel.pid_max=1000000 " >> /etc/sysctl.conf
$ sysctl -p

修改之后,xshll可以登录了。

其实这中间还是蛮曲折的:在执行命令的时候,一直报fork:cannot allocate memory,没办法,只能一直试,后来总算能勉强执行命令了。但是当时是用非root用户登录的,命令需要用root用户执行,在su - root时,也是一直报这个错。然后尝试了阿里云UI中的vnc远程登录也是如此。没办法,只能将一个相对不那么重要的服务先kill掉,然后再切到root用户执行上面的命令。

思考

虽然这台主机中跑了比较多(二十几个)的java模块,但是3万多的线程数,平均一个模块要产生1000+的线程?我的预感是这其中应该有某个(些)模块产生了异常多的线程。

写个脚本验证下:

#!/bin/bash
for pid in `jps | awk '{print $1}'`
do 
  num=`pstree -p $pid | wc -l`
  echo $pid
  echo $num
  echo " "
done

执行结果:

$ ./check_thread.sh 
21056
105
 
15170
162
 
20355
70
 
20422
65
 
9611
144
 
31180
203
 
6029
64
 
22606
183
 
21011
260
 
14932
148
 
21464
175
 
14491
87
 
22747
64
 
1819
99
 
10971
155
 
46556
119
 
9886
47
 
7007
146
 
20707
166
 
21285
81
 
6572
150
 
22318
75
 
9970
59
 
10099
36
 
51827
0
 
9973
54
 
6646
73
 
5047
29228
 
20026
181
 
33087
63

可以看到pid为5047的进程产生了29228个线程,然后根据pid就可以直接找到这个模块了。

解决

第二天上班之后,跟负责这个模块的开发人员反映了这个问题。在一番仔细的查看代码之后,终于是找到了问题的根本所在—连接solr的http连接一直没有关闭导致的。

知道问题所在之后,解决起来就很快了。

至此,一个线上的线程数暴增的问题顺利得到了解决。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章