1. 现象描述
接手了一台入职公司两年零三个月的服务器,突然有一天内存打满,上去看了一下,只有一个vsftpd服务,主要是用来传输日志文件的(B端)。
但这里内存打满,几乎没法操作服务器了,随即找了个风雨交加、夜深人静的时候,重启,钉钉记个代办,过几天在看。
服务器配置:
- 2c4g
2. 排查过程
2.1 第一阶段的排查(top)
根据top的显示,我并没有看到有占用大量内存的进程。
此时我还没有意识到问题的严重性,就是下面大量的lftp,内存占用0.1%。
而且还有一个点我没看到,sleeping的进程有接近3千个。
而且由于内存打满,服务器已经卡死了,基本操作不了,了解到是B端业务用的,所以找了个低峰期重启了。钉钉记了个代办。
2.2 第二阶段的排查(atop)
过了个把星期,我打开cvm监控 发现内存是持续上涨,且没有释放的现象,差不多10天内存就彻底打满。
此时我已经怀疑是不是有大量小进程占用内存不释放导致的了。
2.2.1 使用atop排查内存问题
atop 是一款用于监控 Linux 系统资源和进程的工具,以一定的频率记录系统的运行状态,采集系统资源(CPU、内存、磁盘和网络)使用情况及进程运行情况数据,并以日志文件的方式保存在磁盘中。当实例出现问题时,可获取对应的 atop 日志文件用于分析。
~]# yum -y install atop # 直接安装就行
~]# systemctl start atop # 注意,这东西会一直生成日志文件在本地,排查完问题记得关了,不然会把磁盘打满
这里简单看了下参数,它有个-m参数可以专门看内存方面的监控。
这里注意RSIZE这一列,表示进程实际使用的物理内存,然后我过滤了一个lftp,一共九百多个,而且随着时间推移越来越多,这九百多个进程就占用了2G多的内存(可怜它一共也就3.5G可用内存)。
查到这里,基本也就确定了内存打满的根因了,但还不知道为啥有这么多子进程不释放。
3. 解决办法
我服务器上看了一下,lftp就是个客户端命令,也没有配置文件,由于是root用户启动的,也不好限制进程打开数,于是决定通过进程启动时间过滤,主动杀死非当天打开的lftp进程。
就像下面这样:
3.1 批量杀死进程
生产不缺定业务重要性的情况下,千万不要这样玩,不然绩效D、扣马内、写事故报告少不了(这些都不重要,重要的是影响用户口碑)
紧接着我服务器负载打满,我登不上去了,蟹特。
然后我查了一下,同时大批量(我这里八百多个进程)杀死进程,在这个时间内,会有大量的上下文切换,从而导致系统负载升高(我的2C直接拉满)。
没有办法,只能重启,等过几天我在试试一次kill几十个看看有没有事。
经过几天的等待,这服务器上的lftp进程终于累积到了1142个,给我服务器的内存都快干满了。
3.2 编写脚本和定时任务
经过不断测试,最终成果如下(大佬勿喷,太久没写脚本了,肚子里没有墨水):
[root@VM-26-3-centos ~]# cat kill_lftp.sh
#!/bin/bash
# 20241029 xietangsheng
while true;do
# 同时大批量杀死进程,会导致大量上下文切换,从而导致系统负载急剧升高,可能会卡死系统,这里sleep 60,让系统缓缓
sleep 60
ps -eo pid,comm,lstart|grep lftp|grep -v "$(date +'%b %d')"|awk '{print $1}'|head -n 60|xargs kill &> /dev/null
# kill结果不为0,代表一天前的lftp已经全部杀死,可以退出运行。
if [ $? -ne 0 ];then
echo "$(date) 一天前的lftp程序清理完毕!当前剩余lftp程序数量:$(ps -ef |grep lftp|wc -l)" &>> ./kill_lftp_log/kill_lftp.log
exit
fi
done
定时任务:
# 每周日凌晨执行一次脚本。
00 00 * * 0 sh /root/kill_lftp.sh
3.3 手动执行后
效果嘎嘎好,但我这是B端的业务(就算挂了,也不会影响用户),C端千万别这么整。
4. 问题根因
最后同事找到了原因,本地有一个文件同步脚本,lftp命令是有关闭连接的参数的,但脚本中并没有添加,导致每次文件同步完后,打开的链接没有主动关闭,加上关闭连接的参数就行了。