我的 nginx 单元文件如下,
[root@arif ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
这里,在该[Service]
部分中, 的值Type
等于,forking
这意味着从这里,
以 ExecStart 启动的进程会生成一个子进程,该子进程成为服务的主进程。启动完成后父进程退出。
我的问题是,
- 为什么服务会这样做?
- 这样做有什么好处?
Type=simple
或者其他类似的选项有什么问题?
答案1
为什么服务会这样做?
服务一般不要事实上,这样做。除了这不是一个好的实践,而且“守护进程”的想法确实是错误的之外,服务还能做什么?不是forking
协议所要求的。他们弄错了协议,因为他们实际上正在做别的东西,它被硬塞进forking
协议中,通常是不必要的。
这样做有什么好处?
没有。存在更好的准备通知协议,但实际上没有人说话这协议正确。该服务单位不这样做是因为这样做有利。
Type=simple
或者其他类似的选项有什么问题?
没有什么。事实上,通常来说,准备协议的使用forking
是错误的。正如其他答案中所述,这不是最佳实践。恰恰相反。
简单的事实是,这是一项糟糕的工作中最好的,是应对 nginx 仍然无法关闭的行为的一个避难所。如今,得益于 IBM SRC、daemontools 和其他严肃的服务管理领域 25 年来的鼓励,大多数服务软件都获得了选项,甚至更改了其默认行为,不再试图愚蠢地“守护进程”某些东西。已经在守护进程上下文中。
不过,对于 nginx 来说,情况仍然不是这样。 daemon off
可悲的是,不起作用。正如许多软件曾经错误地将“非守护进程”模式与调试模式混为一谈(但现在通常不再这样做),nginx 不幸地将其与其他事物混为一谈,例如不处理其控制信号。到目前为止,人们已经为此努力了 5 年。
进一步阅读
- 乔纳森·德博因·波拉德 (2015)。Unix 守护进程的就绪协议问题。经常给出的答案。
- 阿德里安·克莱尔 (2013-10-27)。nginx:不要
type=forking
在 systemd 服务文件中使用。 Debian 错误 #728015。 - runit 和 nginx
- 乔纳森·德博因·波拉德 (2001)。 ”不要为了“将守护进程置于后台”而使用 fork()。”。 设计 Unix 守护程序时要避免的错误。经常给出的答案。
- 乔纳森·德博因·波拉德 (2015)。您确实不需要守护进程。真的。。 systemd 恐怖屋。
- StackExchange 上有许多准备协议不匹配的示例:
- https://unix.stackexchange.com/a/401611/5132
- https://unix.stackexchange.com/a/200365/5132
- https://unix.stackexchange.com/a/194653/5132
- https://unix.stackexchange.com/a/211126/5132
- https://unix.stackexchange.com/a/336067/5132
- https://unix.stackexchange.com/a/283739/5132
- https://unix.stackexchange.com/a/242860/5132
答案2
只要相关服务在完成初始化后没有特别支持消息传递 systemd(请参阅 参考资料man systemd-notify
),分叉方法就会用作传统的通知方式:只要父进程还存在,由 报告的服务状态systemctl status
就保持在start
。仅在父进程退出后才
更改为。running
传统守护程序服务的父进程仅在子进程完成设置并准备好使用后才会退出。
如果有任何依赖服务正在等待相关服务准备好使用,则需要此机制。如果不使用传统的守护进程分叉机制来启动不支持特定通知方法的服务systemd
,则服务状态将更改为running
立即,并且任何依赖的服务都会在相关服务准备好使用之前立即启动。
这个原因在中进行了更详细的解释Debian 错误 #728015JdeBP 的答案中已经链接了这一点。
这个原因也是该 bug 被关闭为 的原因wontfix
。