crontab中大量ssh导致机器卡顿问题

问题描述

前段时间不断有人反馈的一个问题,集群的入口登陆节点会定期出现几百个ssh和sed进程,导致入口节点非常卡,输入命令严重迟滞。导致无法正常使用。找了好久没有找到原因。严重的时候,只好重启节点,缓解问题。今天问题又出现了,实在不能忍,决定再找找原因看。

原因追查

以前为了监控这个问题,先使用top -c命令监控进程状况,如果出现了大量ssh和sed进程,再完成使用ps -ef | grep pid来一步步追查进程的父进程。但这实际上是极其愚蠢的做法。因为这些ssh进程只会存在10来秒的时间,加上出现的时候节点会非常卡顿,导致根本来不及找到父进程的父进程是什么。所以问题一直没有眉目。

监视ssh进程

今天突然想起了可以用for loop, sleep和grep更高效的监控问题,思路是在命令行上每间隔3s,使用ps命令查看当前有哪些相关进程。首先监控ssh进程,

1
for i in {1..3000}; do ps -ef | grep ssh; sleep 3; done

大部分的时候输出都是正常,十几秒后就会看到有大量异常的ssh进程出现。
异常ssh截图
异常进程和正常的ssh进程区别很明显,如图,红框中的部分就是导致集群卡顿的ssh进程,进程ssh到其他节点后执行了ntpdate命令。

监视ntpdate进程

ntpdate是一个与时间同步有关的工具。从结果可以可见,这个命令从管理节点ssh到内部节点,再由内部节点向管理节点发送ntpdate时间同步请求。 应该是一个系统服务,但是太多请求同时进行,频度有很高,就会导致卡顿。

进而开始追踪是哪个进程执行了这样的批量ssh操作,方法只需要将上面的grep ssh改成grep ntpdate

1
for i in {1..3000}; do ps -ef | grep ntpdate; sleep 3; done

ntpdate监控

pstree查看进程树

很快找到元凶。如上面截图,有某一个进程执行了命令/usr/bin/perl /usr/bin/nprsh -on node1..336 -e node307 ntpdate 11.11.2.1。但是需要找到执行这个命令的进程。如果使用ps -ef | grep ppid的方法,根据父进程pid一步步追溯,时间来不及。也就是今天,我想到了pstree,这才使得该问题能够顺利解决。

1
2
3
4
# 首先执行下面的监控命令
for i in {1..3000}; do ps -ef | grep ntpdate; sleep 3; done
# 等待异常ssh请求出现的时候,在另一个窗口中执行下面命令
pstree -ahnp # 即可将此刻的进程关系输出来。

多亏了pstree命令,平时虽然也用过,但是这时候才想起来。从pstree的结果中我看到了如下输出:
pstree-crontab

检查crontab

结果显示,发起这么多ssh请求的进程,追溯上去源头竟然是crond进程,也就是系统的crontab守护进程。这就意味着,这些时间同步操作是实际上是被添加到contab中去了的。但是因为我对crontab所知甚少,导致我在这里又停滞了好久。
首先想到的是查看系统当前的所有crontab任务

1
contab -l    # 列出当前用户的crontab任务列表

上面的命令实际上是列出系统当前用户的crontab任务列表,而不是全部用户的crontab任务列表,正确的命令应该如下:

1
cut -d: -f1 /etc/passwd|xargs -i sudo crontab -u {} -l

显示系统一共有4条crontab任务。并且每一条记录都可以确定都与时间同步无关。但是从上面的结果看起因确实应该是crontab。

我曾想,被执行的/usr/bin/perl /usr/bin/nprsh -on node1..336 -e node307 ntpdate 11.11.2.1命令可以确定是保存在某一个文件中的,那么就可以通过搜索文件的内容来定位源头。可是使用了错误的命令导致搜索失败。

1
2
# 正确的命令如下
grep -R "ntpdate" /etc

当然,源文件也可能存在于/usr或者/opt目录下,最有可能在/etc目录下(实际上确实是的)。

因为使用错了命令,导致我错过了用这种方法找到原因的机会。接着我怀疑是否是因为系统的crontab文件被恶意替换了,因此,我打算将系统的/etc/crontab文件与另一个使用同一母盘安全的节点的文件进行对比。这一歪打正着最终让我发现了全部的原因。文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# file: /etc/crontab
# 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

0 0 * * * root /usr/sbin/ntpdate 0.rhel.pool.ntp.org

# For other nodes sync time with node307 every minute
*/1 * * * * root nprsh -on node1..336 -e node307 ntpdate 11.11.2.1

# correct clocksource every half hour
#*/1 * * * * root nprsh -f /home/gj/powerinfo/finaldata/readnodes "echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource"

*/10 * * * * root service ntpd start

最终的原因就是,系统的/etc/crontab文件被某个同学修改了,事后没有还原。

追查时间

看到文件的内容我大致就知道是哪位同学修改的了,还是顺便看看修改时间:

1
stat /etc/crontab

输出如下:文件在5月12号别修改过。
crontab-stat

(看吧,就是这么简单一处配置文件修改,制造了这么多麻烦!!所以root权限不能随便乱给啊!!)

总结

前面追查原因的过程犯了很多错,最大的错误有两点

  1. 不知道使用pstree工具查看进程树关系,好在很快意识过来了;
  2. 对crontab不了解,以为与iptables类似,crontab -l出来的就是系统的全部计划任务;

关于contab的补充

  1. crontab是linux执行定时计划任务的服务;
  2. 用户可以使用命令crontab -e来编辑当前用户的crontab任务,这些信息最重被保存在/var/spool/cron/目录下;
  3. 此外,/etc/crontab文件中可以直接添加系统计划任务,并且这部分雷荣不会显示在任何的crontab -l的输出中;
  4. 此外的此外,/etc/cron.daily/目录下的脚本文件会在每小时的前5min内随意挑选一个时间执行;
  5. 此外的此外的此外,还有/etc/cron.daily/, /etc/weekly//etc/cron.hourly/文件,他么与另一个服务,叫anacron有关

详细的关于crontabanacrontab的内容,可以查看此处鸟哥的linux私房菜-crontab