一、故障现象
接业务侧同事电话,其中一台server无法ssh正常连接,同时也收到宕机短信告警信息。直接ping了下主机地址可以ping通,ssh端口连接提示:ssh_exchange_identification: Connection closed by remote host 。通过管理口登录查看报错:“ login: failure forking: Cannot allocate memory/etc/initscript: fork : Cannot allocate memory ”。截图如下:
二、故障分析与处理
1、强制回收内存
从表现上来看不能fork进程不能分配内存,本来该问题可以直接重启解决,不过为了查到根因。通过从次尝试成功从管理口登录系统。登录后,不过像ps auxf命令执行老半天不出结果,通过top查看观察发现大量postdrop进程:
执行以下三个命令强制回收内存和结束业务进程,希望通过此步能正常进行系统命令操作
//手动强制回收内存
echo 3 > /proc/sys/vm/drop_caches
//上面的执行后,效果不明显,强制kill掉一些业务进程
killall java
killall postdrop
通过上面的三个命令艰难的执行后,一些命令有结果输出,不过像ps auxf 命令执行老半天仍不出结果 。通过查看/proc下的进程号发现有大量进程,尝试通过ls /proc > /mnt/proc.txt 输出到文件---经测试发现文件未能成功生成。
2、查看磁盘空间占用
由于之前也遇到由于磁盘空间满导致内存数据无法sync到磁盘上,导致内存得不到释放,最终造成进程积压的问题。这里也通过df 查看磁盘目录
发现var目录占满,通过清空/var/log下的info等可能出现的大文件 ,发现var目录仍得不到释放。进入/var/spool/postfix/目录下 du maildrop -sh ,发现半天未出现结果。
3、重启或进入单用户
这里可以进行重启或进入单用户任选一个尝试,由于是磁盘耗尽导致的问题,一般重启都可以正常进入系统。通过sync 几次后,重启主机进入系统。通过到/var/spool/postfix/maildrop下验证,发现该目录下占用了大约17G左右的空间---和之间的猜测一致。
重启后,通过观察主机进行的进程,发现cron任务执行时,都会调用sendmail 进程和触发postdrop进程执行。如下:
cron-sendmail.png
查看执行的脚本内容,未发现调用mail 相关的语句。
chkconfig --list|egrep -i 'sendmail|postfix' ,发现postfix进程已被在开机启动中关掉。查看crontab配置,发现如下:
[root@361way.com ~]# cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
三、故障原因
1、原因
通过上面的分析,得出故障原因为:crontab进程在执行时,每执行一次会向root 进行一次汇报。即会调用后面的sendmail 进程和postdrop 进程,邮件文件会存放在/var/spool/postfix/maildrop目录 ,查看logcollect 用户的crontab任务发现, 有几百个crontab任务存在 ---感觉好傻的业务模型。造成maildrop目录文件越堆越多。目录被占满后,导致sendmail和postdrop进程长时间得不到释放。进程越堆越到,直到资源耗尽,ssh连接异常。
2、解决方法
禁用crontab MAILTO功能或crontab中新增自动清理/var/spool/postfix/maildrop目录。当然比较推荐前者,crontab里启用这个本来就是个资源浪费的功能---有查看root下的性能汇报需求者除外。禁用crontab的mailto功能操作步骤为:
vi /etc/crontab ;将‘MAILTO=root’替换成‘MAILTO="",然后service crond restart即可。如不行crontab -e 第一行增加MAILTO="" 。