我在 (VMWare) VM 上使用 Red Hat Linux (RHEL5)。我编写了一个守护进程,它应该一直运行并在启动时自动运行。
昨晚,VM 主机出现了不可恢复的硬件问题,VM 突然停止运行。当它恢复运行后,我的守护进程没有启动,因为 pidfile 仍然存在。
显然这被称为过时的 pidfile 综合症但我不确定缓解此问题的最佳长期方法是什么。我认为启动脚本/etc/rc.d*
应该在启动守护进程之前删除 pidfile,但服务管理脚本/etc/init.d
应该保持不变,这样就service mydaemon start
不会破坏 pidfile。
/etc/rc.d/rc6.d
只具有指向 中的脚本的符号链接/etc/init.d/
,那么我该如何更改它仅在启动时的行为?我可以在目录中创建一个具有更高优先级的附加脚本rc.d
,但这似乎有点不合时宜。有人还建议添加类似“如果正常运行时间少于 1 分钟,则删除 pidfile”但这似乎也很 hacky。
有什么想法、解决方案或最佳实践吗?
答案1
答案2
感谢@Dennis 和@coredump 的提示。
我发现了一些额外的信息,帮助我解开了谜团。
我想知道为什么其他守护进程都能正常恢复。原来有代码可以在启动时
/etc/rc.d/rc.sysinit
清理所有 pid 文件。/var/run
/var/lock
我已将我的守护进程配置为将其 pidfile 放在其他地方,因为 SELinux 阻止我“使用可能标记错误的文件”。
由于 SELinux 的问题,我还没有修复它,但我认为答案是“把你的 pidfile 放进去/var/run
,/var/lock
下次它就会工作了”
答案3
脚本是一样的,启动过程只是对 sysvinit 脚本执行‘启动’操作。
为什么不检查 pid 文件上的 pid 是否正确,如果不正确,就删除它并使用正确的 pid 创建一个新的?
编辑:您可以使用 pidfile 来 grep ps 以查看进程是否仍然存在。或者反过来。检查 RedHat initscripts,我相信他们有一些辅助函数可以做到这一点,比如pidofproc
。
答案4
即便现在有了 systemd,PID 文件仍然被使用和放错位置的情况也并不罕见。特别是对于未随发行版附带的软件。通常,我看到其他进程正在使用与(强制)重启之前使用的服务相同的 PID,然后认为该服务已在运行。遗憾的是,这种情况并非不可能,因为 PID 在重启后再次从 1 开始,然后每启动一个进程就加 1。我最终决定创建一个在早期启动期间设置随机 PID 的服务。这应该使得 PID 被重用的可能性很小。
为此,我在 /etc/systemd/system/randomize-pid.service 创建了此服务:
[Unit]
Description=Set next upcoming PID to a random value
DefaultDependencies=no
# sysctl may be used to adjust highest allowed PID (pid_max)
After=systemd-sysctl.service
Conflicts=shutdown.target
Before=shutdown.target
# Run before starting "regular" services that have
# DefaultDependencies set to yes.
Before=sysinit.target
ConditionPathExists=/proc/sys/kernel/pid_max
ConditionPathExists=/proc/sys/kernel/ns_last_pid
ConditionPathIsReadWrite=/proc/sys/kernel
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'shuf -n 1 -i 1-$(cat /proc/sys/kernel/pid_max) > /proc/sys/kernel/ns_last_pid'
TimeoutSec=90s
[Install]
WantedBy=multi-user.target
然后启用它:
systemctl enable randomize-pid.service
这需要检查点/重启在内核中启用,但我相信这是大多数发行版的默认设置。