避免使用 PID 文件、crons 或任何其他试图评估不是其子进程的进程。
在 UNIX 中有一个很好的理由,您只能等待您的孩子。任何试图解决这个问题的方法(ps 解析、pgrep、存储 PID,...)都是有缺陷的,并且存在漏洞。直接说不。
相反,您需要将监控您的进程的进程作为该进程的父进程。这是什么意思?这意味着只有您的进程启动的进程才能可靠地等待它结束。在 bash 中,这绝对是微不足道的。
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
上面的 bash 代码在 until 循环中运行 myserver。第一行从myserver 开始并等待它结束。当它结束时,until 检查它的退出状态。如果退出状态是0,这意味着它优雅地结束了(这意味着你要求它以某种方式关闭,并且它成功地关闭了)。在这种情况下,我们不想重新启动它(我们只是要求它关闭!)。如果退出状态是 not 0,until 将运行循环体,它会在 STDERR 上发出错误消息并重新启动循环(回到第 1 行)1 秒后。
我们为什么要等一秒钟?因为如果myserver 的启动顺序出现问题并且它立即崩溃,您将有一个非常密集的循环不断重启和崩溃。 sleep 1 消除了压力。
现在您需要做的就是启动这个 bash 脚本(可能是异步的),它会监控 myserver 并在必要时重新启动它。如果您想在启动时启动监视器(使服务器“存活”重新启动),您可以使用 @reboot 规则在用户的 cron(1) 中安排它。使用crontab 打开您的 cron 规则:
crontab -e
然后添加一个规则来启动你的监控脚本:
@reboot /usr/local/bin/myservermonitor
或者;查看 inittab(5) 和 /etc/inittab。您可以在其中添加一行以使 myserver 从某个初始级别开始并自动重生。
编辑。
让我补充一些关于为什么不使用 PID 文件的信息。虽然它们很受欢迎;他们也有很大的缺陷,你没有理由不以正确的方式去做。
考虑一下:
-
PID回收(杀错进程):
-
/etc/init.d/foo start:启动foo,将foo的PID写入/var/run/foo.pid
- 过了一会儿:
foo 莫名其妙地死了。
- 稍后:任何启动的随机进程(称为
bar)都会使用随机 PID,想象一下它会使用 foo 的旧 PID。
- 你注意到
foo已经消失了:/etc/init.d/foo/restart读取/var/run/foo.pid,检查它是否还活着,找到bar,认为它是foo,杀死它,开始一个新的foo。
PID 文件过时。您需要过于复杂(或者我应该说是不平凡的)逻辑来检查 PID 文件是否过时,并且任何此类逻辑都容易受到1. 的攻击。
如果您甚至没有写入权限或处于只读环境中怎么办?
这是毫无意义的过度复杂化;看看我上面的例子是多么简单。完全不需要复杂化。
另请参阅:Are PID-files still flawed when doing it 'right'?
顺便说一句; 比 PID 文件更糟糕的是解析 ps!永远不要这样做。
-
ps 非常不便携。虽然您几乎可以在每个 UNIX 系统上找到它;如果您想要非标准输出,它的参数会有很大差异。而且标准输出仅供人类使用,不能用于脚本解析!
- 解析
ps 会导致大量误报。以ps aux | grep PID 为例,现在想象有人以某处的数字作为参数启动一个进程,该参数恰好与您盯着守护进程使用的 PID 相同!想象一下,两个人开始一个 X 会话,而你正在寻找 X 来杀死你的会话。就是各种不好。
如果您不想自己管理流程;有一些非常好的系统可以作为您流程的监控器。例如,查看runit。