Linux 使用PID文件杀死守护进程

Linux 使用PID文件杀死守护进程,linux,unix,daemon,pid,Linux,Unix,Daemon,Pid,在运行守护程序时,一个常见的Linux/UNIX习惯用法是生成守护程序,并创建一个只包含守护程序进程ID的PID文件。这样,要停止/重新启动守护进程,只需使用脚本kill$(cat mydaemon.pid) 现在,这里有很多不一致状态的机会。假设运行守护进程的机器被强制关闭,然后重新启动。现在您有了一个PID文件,它引用了一个不存在的进程 好吧,没问题。。。您的守护进程只会尝试杀死不存在的进程,发现它不是一个真正的进程,然后照常继续 但是。。。如果它是一个真正的进程,而不是你的守护进程呢?如果

在运行守护程序时,一个常见的Linux/UNIX习惯用法是生成守护程序,并创建一个只包含守护程序进程ID的PID文件。这样,要停止/重新启动守护进程,只需使用脚本
kill$(cat mydaemon.pid)

现在,这里有很多不一致状态的机会。假设运行守护进程的机器被强制关闭,然后重新启动。现在您有了一个PID文件,它引用了一个不存在的进程

好吧,没问题。。。您的守护进程只会尝试杀死不存在的进程,发现它不是一个真正的进程,然后照常继续

但是。。。如果它是一个真正的进程,而不是你的守护进程呢?如果这是别人的过程,或者其他重要的过程呢?你没有办法知道-所以杀死它是潜在的危险。一种可能是检查进程的名称。当然,这也不是万无一失的,因为没有理由其他进程可能没有相同的名称。特别是,例如,如果您的守护进程在一个解释器(如Python)下运行,在这种情况下,进程名称将永远不会是唯一的—它将只是“Python”,在这种情况下,您可能会无意中杀死其他人的进程


那么,我们如何处理这样一种需要重新启动守护进程的情况呢?我们怎么知道PID文件中的PID必然是守护进程呢?

您只是不断添加妄想症的层次:

  • pid文件
  • 进程名称匹配
  • 一些沟通渠道/金丝雀
为了确保pid在重新启动后不会过时,最重要的是将其存储在一个位置,该位置保证每次重新启动时都会被清除

对于流程名称匹配,您实际上可以在fork/exec点重新定义流程的名称,这将允许您使用一些唯一的名称


沟通渠道/金丝雀稍微复杂一些,容易出现一些问题。如果守护进程创建了命名套接字,那么套接字的存在+与守护进程连接和通信的能力将被视为进程正在运行的证据。

如果您真的想为用户提供脚本,您可以让守护进程自己管理其pidfile,并添加一个
atexit
和一个
SIGABRT
处理程序来取消pidfile的链接,即使是在不干净的关机情况下

更多方法还包括在pidfile中存储进程启动时间。与易失性存储(例如,
/var/run
)一起,这是一种非常可靠的流程识别方法。这使得kill命令更复杂一些


但是,我个人认为,守护程序开发人员不应该(太)在意这一点,而应该让目标平台以管理守护程序的方式(systemd、upstart、好的ol'SysV init脚本)来处理这一点。他们通常有更多的知识:例如,systemd将乐于接受一个根本不分叉的守护进程,允许它直接监视其状态,而不需要PID文件。然后,您可以为最常见的解决方案提供配置文件(目前可能是systemd,因为Debian也将迁移到它,因此它也将很快进入ubuntu),这些解决方案通常比完整的守护进程进程管理更容易编写。

通常您会向其发送一个SIGTERM,这与没有标志的
kill
相同,我相信你是从哪个角度问的:从想要管理守护程序的系统程序员的角度,还是从守护程序开发人员的角度,谁想要为用户提供一个脚本来启动/停止自己的守护程序?这是一个有趣的问题。。。我是从守护程序开发人员的角度考虑的,但我不明白为什么这很重要。守护程序管理器(如systemd)通常一直运行,并且是PID 1。因此,它完全了解所有守护进程(因为它们在分叉和分离后即是PID 1的直接子进程),这使它处于稍微不同的位置。事实是,根本没有无种族限制的方式向非子进程发送信号。如果您觉得您绝对需要一种在无种族竞争管理器中杀死守护进程的方法,那么您应该以不同的方式管理您的守护进程。(通过Unix套接字通信关机,使用systemd或其他init守护进程,或者创建自己的管理进程来生成和杀死守护进程。)我认为甚至有一些安全相关机制使用
(启动时间,pid)
-元组来安全地识别进程。由于我找不到这方面的消息来源,我更愿意在评论中提及这一点。也许有人知道linux是用哪种机制实现的?