朋友弄了一个小项目,要我帮忙做下 Linux 系统运维,上线一段时间后,发现项目偶尔会挂掉导致服务不可用。开发朋友一时之间也没空去研究项目奔溃的根因,只好由我这个运维先写一个项目进程自拉起脚本,通过 Linux 任务计划每分钟检查一下进程是否存在来避免项目挂了没人管的情况。
自拉起脚本很简单,随便写几行就搞定了:
#!/bin/bash processcount=$(pgrep my_app|wc -l) cd $(cd $(dirname $0) && pwd) if [[ 0 -eq $processcount ]] then echo "[ $(date) ] : my_app is down, start it!" | tee -ai ./checkprocess.log bash ./start.sh #这里是项目的重启脚本 else echo my_app is OK! fi
然后丢到 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: <[email protected]_server.localdomain> X-Original-To: root Delivered-To: [email protected]_server.localdomain Received: by app_server.localdomain (Postfix, from userid 0) id 78DB5403E2; Fri, 25 Mar 2016 21:19:02 +0800 (CST) From: [email protected]_server.localdomain (Cron Daemon) To: [email protected]_server.localdomain Subject: Cron <[email protected]_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: <[email protected]_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 <[email protected]> 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: <[email protected]_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/ 这个关键词了解下。
好了,本文分享到此,希望对你有所帮助!
大神,我表示看不懂!!
我也表示看不懂。
看懂有点迷糊
你个坑货 之前找你帮忙搞下apache经常死掉 然后搞个自动重启的脚本 到现在没搞定呢 :razz:
谢谢,张哥分享,不过还是很多人用不到的
一直在关注你把http改成https,半年过去了,我感觉效果差极了。目前来看你今年以来的文章不仅https没有收录,连http也没有收录了。目前就百度一直在宣传https吧,虽然百度也一直没收录https,其他搜索引擎好像都没啥表示。最让我困惑的是最近豆瓣也改成了https,难道仅仅是出于安全考虑吗。没有收录对一个依赖seo来流量的网站是致命的。不知博主怎么看待这个问题。
目前来看,比较前卫,也没L 用,个人博客我也不推荐折腾https。
我使用https主要是为了折腾学习,然后跟上趋势。
我的也是https,最近我的文章不到一天百度就收录了,虽然是http的链接,但是也是有所改变的。
也许是我博客的问题吧
你好,请问你是怎么设置的呀,我的也是https的,但是收录一直不乐观,而且还在掉
刚查看了一下你的收录情况,貌似也不是很乐观,今年貌似只有2月份的一条 :???:
不是啊,是不是看错了呃
liunx 系统的不太懂了
哈哈,Jager大神,发现你的静止复制,删掉了咯 :mrgreen:
Linux系统很安全
博主的网站挺快的,请问你有用CDN吗,免费的百度云加速,好像没效果一样,能不能推荐一下你用的CDN和图片存储方法
没有真实去接触或折腾过Linux,真的看不太懂,只能路过了
还是不懂。。
我遇到问题就是里面绝对路径问题和一些变量,博主你这个我还真没有碰到过,这里吸收下
我遇到的问题,是计划任务里的脚本里,已经把导出的路径改了,但定时后还是导出到原来的文件中去了,不知道怎么回事。
贴出你的代码才好分析~~
没事,找到原因了,还是简单的环境变量问题,用了ifconfig命令。
表示数据库自动备份脚本遇到过这个问题,手动执行一切正常, 放crontab里面就没有执行备份,直接进行了打包,导致近一周数据未备份。。。。也是看日志发现脚本里面的mysqldump命令路径不对。。。R了G了