我有一堆服务(例如C0
,C1
… C9
),这些服务只能在一个服务S
完成其初始化并完全运行并为其他服务做好准备后才能启动。如何用systemd安排呢?
在systemd中使用路径激活和目标订购服务中,假定服务S
具有一种写出某种标记文件的机制。相反,在这里假设我对服务S
运行的程序拥有完全控制权,并且可以在需要时向其中添加systemd机制。
我有一堆服务(例如C0
,C1
… C9
),这些服务只能在一个服务S
完成其初始化并完全运行并为其他服务做好准备后才能启动。如何用systemd安排呢?
在systemd中使用路径激活和目标订购服务中,假定服务S
具有一种写出某种标记文件的机制。相反,在这里假设我对服务S
运行的程序拥有完全控制权,并且可以在需要时向其中添加systemd机制。
Answers:
如果C
服务需要等待S
准备就绪以便它们可以打开与之的套接字连接,则不一定需要这样做。而是可以利用服务管理者提早监听套接字打开的优势。
包括Laurent Bercot的s6(我的nosh工具集)和systemd 在内的多个系统都有一些方法可以在早期打开监听套接字,这是设置服务的第一件事。它们都涉及服务程序打开侦听套接字的其他问题,并且服务程序在被调用时将侦听套接字作为已打开的文件描述符接收。
具体来说,使用systemd,可以创建一个定义监听套接字的套接字单元。systemd打开套接字单元并进行设置,以使内核网络子系统正在侦听连接;并在生成处理与套接字连接的进程时将其作为打开的文件描述符传递给实际服务。(它可以通过两种方式做到这一点,就像inetd
可能的那样,但是对Accept=true
vs Accept=false
服务的详细讨论超出了此答案的范围。)
重要的一点是,不一定需要更多的排序。内核将队列中的客户端连接批处理成批,直到服务程序初始化,然后准备接受它们并与客户端对话。
systemd拥有一套它可以理解的就绪协议,即通过Type=
服务单元中的设置按服务指定服务。这里感兴趣的特定准备协议是notify
准备协议。使用它,告诉systemd期望来自该服务的消息,并且当该服务准备就绪时,它会发送一条标记为就绪的消息。systemd会延迟其他服务的激活,直到标记为就绪为止。
利用这一点涉及两件事:
S
,使其调用类似Pierre-Yves Ritschard的notify_systemd()
函数或Cameron T Norman的notify_socket()
函数。Type=notify
和NotifyAccess=main
。 该NotifyAccess=main
限制(这是默认值),是因为systemd需要知道忽略来自恶作剧(或只是简单的故障)计划的消息,因为系统上的任何进程都可以发送邮件到systemd的通知插座。
首选使用Pierre-Yves Ritschard或Cameron T Norman的代码,因为它不排除在UbuntuBSD,Debian FreeBSD,实际的FreeBSD,TrueOS,OpenBSD等上具有此机制的可能性;systemd作者提供的代码不包括在内。
要避免的陷阱是systemd-notify
程序。它有几个主要问题,其中最重要的一个问题是与它一起发送的消息最终可能被systemd未经处理而丢弃。在这种情况下,最主要的问题是它不能作为服务的“主”进程运行,因此必须使用打开S
对系统中每个进程的服务的就绪通知NotifyAccess=all
。
要避免的另一个陷阱是认为该forking
协议更简单。它不是。正确执行此操作需要等到程序的所有工作线程都运行后,才能分叉和退出父进程。这与绝大多数分叉的恶魔实际上分叉的方式不符。
sd_notify()
。系统手册页。Freedesktop.org。systemd-notify
。系统手册页。Freedesktop.org。请参考的手册页systemd.service(5)
,特别是有关Type =的部分,每种服务类型都有不同的方式供Systemd确定可以为其他服务提供功能:
如果为Type=simple
,则应在启动守护程序之前安装其通信通道(例如,systemd通过套接字激活设置的套接字)。
如果为Type=forking
,则在启动完成并设置所有通信通道后,预计父进程将退出。
如果为Type=dbus
,则期望守护程序在D-Bus总线上获取名称,此时systemd将继续启动后续单元。
如果为Type=notify
,则期望守护程序sd_notify(3)
在启动完成后通过或等效调用发送通知消息。发送此通知消息后,systemd将继续启动后续单元。
对于最后一个选项(通过发送消息sd_notify
),您可以使用该systemd-notify
实用程序,并记住使用授予它访问权限NotifyAccess=all
。
既然您可以控制服务S
,则可以自由选择适用于您的用例的最佳选项,或者只是最容易实现的选项。
像这样:
服务
[Unit]
Description=My main Service
[Service]
Type=notify
ExecStart=/usr/bin/myBinary
服务中心
[Unit]
Description=Dependent service number 0
PartOf=S.service
C1服务
[Unit]
Description=Dependent service number 1
PartOf=S.service
C9.service
[Unit]
Description=Dependent service number 9
PartOf=S.service
/ usr / bin / myBinary 在初始化完成后进行sd_notify READY = 1调用。
根据您希望依赖项的行为方式,可以使用PartOf,Requires或BindsTo或others。
systemd.service(5)
,NotifyAccess=all
将接受来自所有邮件服务的对照组的成员,这并不能意味着只是系统中的任何恶意进程。对于大多数用例来说,这是足够安全的。另外,您对可移植到其他操作系统的担忧与OP无关,因为此处我们已经讨论了Systemd。