一、问题的由来
昨天晚上回家突然被群里的小伙伴儿通知说某台服务器登录不了,出现如下提示:
ssh_exchange_identification:
read:Connection reset by peer
我赶紧尝试登录,果然出现了,然后运维的在机房一查说资源耗尽了:
然后老大就开始问里面都有什么我们知道的服务,评估一下是否能重启,重启后都需要开启哪些服务,我就直接说了我知道的两个CI 服务和一个我最近部署的定时任务的服务,一想到最近部署,心里咯噔以下,不会是我这个定时任务引起的吧 ,一时半会儿过去了,大家都不说话,在群里各种讨论利用redis 什么漏洞可以登录进去, 但是大家都不知道怎么弄啊。因为机器上有很多不知道的服务,不能贸然重启解决,得想其他的方法登录进去,要知道是什么服务把资源耗光了,治本是关键。突然buddy灵机一动,用浏览器访问jenkins服务url后面加个exit后停掉了jenkins ,这时再用ssh就能登录到机器上,运维的小伙伴儿定位到内存硬盘都没事,最后锁定是进程数满了。查看系统限制用户打开的最大进程数:
ulimit -a
出现 max user processes 的值是65535 ,也就是说当前用户打开的进程数已经达到了65535
这个值得来源:
cat /etc/security/limits.d/90-nproc.conf
文件中* soft nproc 65535 , 一般还有 * hard nproc
如需要修改这个值,则需在 /etc/security/limits.conf 中修改 ,普通用户是受 /etc/security/limits.d/90-nproc.conf影响,还要修改这里面的值
最终上面的值都是受全局的kernel.pid_max的值的影响, 如果kernel.pid_max的值是1000 ,上面都改成了65535,最终用户能打开的最大进程数还是1000
查看全局pid_max :
cat /proc/sys/kernel/pid_max
或者:
sysctl kernel.pid_max
我的是fedora27,所以这里使用sysctl
修改这个值,直接修改 /proc/sys/kernel/pid_max文件 ,但是这样机器重启就没了,永久生效的方法:
直接在/etc/sysctl.conf中添加:
kernel.pid_max=65535
二、知其然,知其所以然
上面巴拉巴拉了一堆,修改用户的最大进程数限制还是没有治标啊,如果进程一直增加,这个限制在不久的将来还是会打破把, 既然已经定位到时进程数满的问题,那就来看看是哪个进程对应的文件句柄数一直在增加:
ps -eLf | awk '{print $2}' | sort | uniq -c | sort -rn | head -n 10
或者
lsof -n | awk '{print $2}' |sort | uniq -c | sort -rn | head -n 10
第一列就是进程打开的文件句柄数,第二列是对应的进程id:
可以看到最大的进程数对应的进程是4214 ,我们查看一下这个4214 是哪个端口占用:
netstat -tulnp | grep 4214
查到的端口是 35000,看到35000,呀,这不是我前两天部署上的服务吗,果然是我的服务造成的, 为什么我的服务会导致进程数一直增加呢, 突然想起来 里面有个调用rpc服务获取数据的代码,好像我没有调用close操作,赶紧一检查验证一下,果然,在我本地测试,进程数蹭蹭的往上涨。找到问题的根源所在了,直接 修改代码,把打开的Socket 连接加上一个finally {scoketClient.close();}完美解决,再次观察进程数,一切正常,此时一万只草拟吗从心里飞过。这里要跟所有的16个运维童鞋和部门内部童鞋说声抱歉,我埋了个大坑,害你们半夜起来折腾了一个多小时。真心跟你们说声对不起
三、总结
经过这次线上事件,让我牢记打开的IO,一定要记得关闭,虽然不关闭现在没什么影响,但是上线后运行的时间稍长一些就会非常危险,也让我再次深刻理解了Linux系统的一切皆文件,一切皆IO ,任何一个命令,包括文件的操作,网络Socket的建立都是在打开文件,打开文件会有相对应的文件句柄,如果超过这个句柄最大限制,内核为了保护系统,就会提示资源耗尽,禁止任何操作,包括ssh登录的操作,这个文件句柄的理解是不是就是文件描述符,刚好最近也在看《Unix/Linux系统编程手册》 、《深入理解计算机操作系统》和《现代操作系统》,来了解一下这个神秘的东西。