解决硬重启杀死守护进程后 pidfile 过期的问题

解决硬重启杀死守护进程后 pidfile 过期的问题

我在 (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 的提示。

我发现了一些额外的信息,帮助我解开了谜团。

  1. 我想知道为什么其他守护进程都能正常恢复。原来有代码可以在启动时/etc/rc.d/rc.sysinit清理所有 pid 文件。/var/run/var/lock

  2. 我已将我的守护进程配置为将其 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

这需要检查点/重启在内核中启用,但我相信这是大多数发行版的默认设置。

相关内容