5

分享一次Linux任务计划crontab不执行的问题排查过程

 3 years ago
source link: https://zhang.ge/5093.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
分享一次Linux任务计划crontab不执行的问题排查过程 | 张戈博客
Jager · 4月5日 · 2016年linux 694次已读

朋友弄了一个小项目,要我帮忙做下Linux系统运维,上线一段时间后,发现项目偶尔会挂掉导致服务不可用。开发朋友一时之间也没空去研究项目奔溃的根因,只好由我这个运维先写一个项目进程自拉起脚本,通过Linux任务计划每分钟检查一下进程是否存在来避免项目挂了没人管的情况。

自拉起脚本很简单,随便写几行就搞定了:

#!/bin/bash
processcount=$(pgrep my_app|wc -l)
cd $(cd $(dirname $0) && pwd)
if [[ 0 -eq $processcount ]]
echo "[ $(date) ] : my_app is down, start it!" | tee -ai ./checkprocess.log
bash ./start.sh #这里是项目的重启脚本
echo my_app is OK!

然后丢到 crontab,1分钟执行一次:

* * * * * bash /data/app_server/checkprocess.sh >/dev/null 2>&1

本以为万事大吉了,结果还是坑了,进程再一次挂了,尼玛什么鬼?

一、检查日志

根据经验,先看一下crontab的日志:

tail /var/log/messages

没发现相关日志,看来不是打印到了这,于是查看了下crontab的默认日志位置:

tail /var/log/cron

Mar 25 21:40:01 li733-135 CROND[1959]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)
Mar 25 21:40:01 li733-135 CROND[1960]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Mar 25 21:40:01 li733-135 CROND[1961]: (root) CMD (/usr/sbin/ntpdate pool.ntp.org > /dev/null 2>&1)
Mar 25 21:41:01 li733-135 CROND[2066]: (root) CMD (sh /data/app_server/checkprocess.sh >/dev/null 2>&1)

很明显,任务计划确实在正常执行着,看来问题在脚本上了。

二、检查脚本

①、直接执行

检查脚本第一步,直接按照crontab里面的命令行,执行脚本:

sh /data/app_server/checkprocess.sh
[ Fri Mar 25 21:25:01 CST 2016 ] : my_app is down, start it!
sh /data/app_server/checkprocess.sh
my_app is OK!

结果进程正常拉起了!

直接执行成功,而放到crontab就失败,经验告诉我肯定的脚本环境变量有问题了!

②、环境变量

于是在脚本里面载入环境变量:

#!/bin/bash
#先载入环境变量
source /etc/profile
#其他代码不变

然后手工把进程杀死,等待自拉起,结果... 还是不行!

③、系统邮件

经验告诉我,crontab执行失败,如果没有屏蔽错误的话,会产生一个系统邮件,

位置在 /var/spool/mail/root

所以,我把crontab里面的 2>&1 这个屏蔽错误先取消掉,等待几分钟查看邮件。

cat /var/spool/mail/root 发现有如下报错:

From [email protected] Fri Mar 25 21:30:02 2016
Return-Path: <root@app_server.localdomain>
X-Original-To: root
Delivered-To: root@app_server.localdomain
Received: by app_server.localdomain (Postfix, from userid 0)
id 78DB5403E2; Fri, 25 Mar 2016 21:19:02 +0800 (CST)
From: root@app_server.localdomain (Cron Daemon)
To: root@app_server.localdomain
Subject: Cron <root@app_server> bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325131902.78DB5403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:19:02 +0800 (CST)
start.sh: line 4: /sbin/sudo: No such file or directory #sudo命令找不到!我次奥·~

居然是脚本里面的sudo执行失败了,找不到这个文件。看来单纯的载入 profile 不一定靠谱啊!

③、修复脚本

知道问题所在,解决就简单了,粗暴点,直接写入sudo的绝对路径 /usr/bin/sudo

继续测试自拉起,结果... 还是不行!R了G了!!

三、最终解决

继续查看了下系统邮件,发现如下信息:

Subject: Cron <root@free-node-us> source /etc/profile;bash /data/app_server/checkprocess.sh >/dev/null
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Message-Id: <20160325132403.0E8E1403E2@app_server.localdomain>
Date: Fri, 25 Mar 2016 21:24:03 +0800 (CST)
sudo: sorry, you must have a tty to run sudo #原来是这个问题!

很明显,提示了sudo必须需要tty才能执行,解决很简单,取消这个限制即可!

编辑 /etc/sudoers ,找到 Defaults    requiretty, 然后注释掉这行:

vim /etc/sudoers
#Defaults requiretty

最后使用 :x! 或 :wq! 强制保存即可。

结果观察还是报了相同的错误!原来改完这个sudo并不会影响已经运行的crontab,所以需要重启crontab服务刷新下设置:

service crond restart

这下终于可以了!

四、分析总结

Linux系统里面计划任务,crontab 没有如期执行这是运维工作中比较常见的一种故障了,根据经验,大家可以从如下角度分析解决:

①、检查crontab服务是否正常

这个一般通过查看日志来检查,也就是前文提到的 /var/log/cron 或 /var/log/messages,如果里面没有发现执行记录,那么可以重启下这个服务:service crond restart

②、检查脚本的执行权限

一般来说,在crontab中建议使用 sh 或 bash 来执行shell脚本,避免因脚本文件的执行权限丢失导致任务失败。当然,最直接检查就是人工直接复制crontab -l 里面的命令行测试结果。

③、检查脚本需要用到的变量

和上文一样,通常来说从crontab里面执行的脚本和人工执行的环境变量是不一样的,所以对于一些系统变量,建议写绝对路径,或使用witch动态获取,比如  sudo_bin=$(which sudo) 就能拿到 sudo在当前系统的绝对路径了。

④、放大招:查看日志

其实,最直接最有效的就是查看执行日志了,结合crontab执行记录,以及crontab执行出错后的系统邮件,一般都能彻底找到失败的原因了!当然,要记住在crontab中如果屏蔽了错误信息,就不会发邮件了。

这又让我想起了如果crontab未屏蔽日志,可能会导致硬盘 inode 爆满 ==> 历史文章传送门 ,感兴趣的童鞋也可以谷歌一下 /var/spool/clientmqueue/ 这个关键词了解下。

好了,本文分享到此,希望对你有所帮助!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK