默认情况下,当 systemd 被要求重新启动服务时,它会停止第一个进程,然后启动第二个进程,因此时间线如下所示:
PROCESS A
--------[stopped]
[started]--------
PROCESS B
我无法承受任何服务停机时间,但是两个服务一起启动是可以的,所以我希望时间线如下所示:
PROCESS A
------------------[stopped]
[started]------------------
PROCESS B
我怎样才能做到这一点?
答案1
我建议一个解决方法:创建该服务的多个实例,然后在停止第一个实例之前启动第二个实例。
配置您的单元文件,例如命名为:(这是必需的):/etc/systemd/system/[email protected]
@
[Install]
# for example
WantedBy=multi-user.target
[Unit]
# for example
Description=mymonitor %i
[Service]
# for example; the %i may not be useful in your case
ExecStart=/path/to/monitor %i
发现它:
sudo systemctl daemon-reload
启用它:
sudo systemctl enable mymonitor@thisone
...并且在启动时,您将使用实例名称“thisone”启动监视器。
现在,当您想要重新启动服务时,您可以使用脚本进行简单的测试:
#!/bin/sh
if systemctl is-active mymonitor@thisone > /dev/null
then
systemctl start mymonitor@thatone &&
systemctl stop mymonitor@thisone
else if systemctl is-active mymonitor@thatone
systemctl start mymonitor@thisone &&
systemctl stop mymonitor@thatone
else
echo Houston, we have a problem
# or perhaps you want to start, with: systemctl start mymonitor@thisone
fi
如果您需要在开始和停止之间有更多的重叠时间,请使用以下内容构建它:
# ...
if systemctl start mymonitor@thisone
then
sleep 7
systemctl stop mymonitor@thatone
fi
# ...
答案2
我认为在没有负载均衡器、防火墙规则或重新路由流量的情况下,不可能在一个节点上直接实现这一目标。它肯定超出了 systemd 的范围。
原因是服务会占用一个监听端口。为了实现零停机,决不能将客户端定向到不存在的端口或关闭服务的端口。但是您不能同时在同一端口和 IP 上运行Process A
和Process B
。
为了实现零停机,您必须在与旧端口不同的端口上启动新进程,然后使用防火墙规则或负载均衡器等功能将流量从旧端口重定向到新端口。然后你必须等待旧客户端断开连接。然后(并且只有那时)您才能关闭旧服务。
实现此目的的“正常”方法是使用位于负载均衡器后面的两个节点(两个服务器)。在这种情况下,您可以通过临时重新配置负载均衡器以指向另一个节点来重新启动节点,并在重新启动完成后再次将其重新配置回来。
这远远超出了 systemd 的范围。如果您想使用防火墙自动执行该过程并自动重新配置服务以使用不同的端口,您可以构建一组复杂的脚本来实现它,并将其作为自定义reload
选项连接。