一、故障现象

接业务侧同事电话,其中一台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 ”。截图如下:
allocate-memory.png

二、故障分析与处理

1、强制回收内存

从表现上来看不能fork进程不能分配内存,本来该问题可以直接重启解决,不过为了查到根因。通过从次尝试成功从管理口登录系统。登录后,不过像ps auxf命令执行老半天不出结果,通过top查看观察发现大量postdrop进程:

postdrop.png

执行以下三个命令强制回收内存和结束业务进程,希望通过此步能正常进行系统命令操作

1//手动强制回收内存
2echo 3 > /proc/sys/vm/drop_caches
3//上面的执行后,效果不明显,强制kill掉一些业务进程
4killall java
5killall postdrop

通过上面的三个命令艰难的执行后,一些命令有结果输出,不过像ps auxf 命令执行老半天仍不出结果 。通过查看/proc下的进程号发现有大量进程,尝试通过ls /proc > /mnt/proc.txt 输出到文件---经测试发现文件未能成功生成。

2、查看磁盘空间占用

由于之前也遇到由于磁盘空间满导致内存数据无法sync到磁盘上,导致内存得不到释放,最终造成进程积压的问题。这里也通过df 查看磁盘目录

df-var.png

发现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配置,发现如下:

 1[root@361way.com ~]# cat /etc/crontab
 2SHELL=/bin/bash
 3PATH=/sbin:/bin:/usr/sbin:/usr/bin
 4MAILTO=root
 5HOME=/
 6# For details see man 4 crontabs
 7# Example of job definition:
 8# .---------------- minute (0 - 59)
 9# |  .------------- hour (0 - 23)
10# |  |  .---------- day of month (1 - 31)
11# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
12# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
13# |  |  |  |  |
14# *  *  *  *  * 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=”” 。

后记:

另外,这个问题和Suse工程师也沟通过,该问题更多的是操作规范性的范畴。如果在每个crontab任务后面加上1>/dev/null 2>&1 ,就不会出现邮件调用到maildrop目录的问题了。这里由于crontab任务过多,使用了在用户的crontab配置首行增加MAILTO=””的方法。