![Systemd 延迟重新启动失败的服务,似乎添加了 30 个睡眠时间](https://linux22.com/image/214367/Systemd%20%E5%BB%B6%E8%BF%9F%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8%E5%A4%B1%E8%B4%A5%E7%9A%84%E6%9C%8D%E5%8A%A1%EF%BC%8C%E4%BC%BC%E4%B9%8E%E6%B7%BB%E5%8A%A0%E4%BA%86%2030%20%E4%B8%AA%E7%9D%A1%E7%9C%A0%E6%97%B6%E9%97%B4.png)
(最初将其发布在 stackoverflow 上,但被要求将其移至此处。)我有一个作为服务运行的 python 守护进程,有时其中几个正在为需要相同功能的不同进程(p0、p1 等)运行。我注意到,当服务失败时,有时服务需要很长时间才能恢复,需要 2 到 3 分钟。通常我会看到服务在几秒钟内恢复正常。
kill -9
我在进程上运行了一个脚本来测试 systemd 是否会重新启动服务并systemctl status myapplication@p1
每 30 秒打印一次,直到服务再次运行(其中 3 个服务正在运行)。我注意到,当一个或多个服务在状态消息结束时恢复所需的时间比预期要长时,sleep 30
CGroup 的末尾就会出现这个,并且它的 PID 在每次命令调用之间都会发生变化status
。
* myapplication.service - my application service for p1.
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: activating (start) since Fri 2022-03-25 14:48:27 UTC; 26s ago
Cntrl PID: 1335258 (myapplication)
Tasks: 5 (limit: 9505)
Memory: 3.3M
CPU: 1.442s
CGroup: /system.slice/system-myapplication.slice/[email protected]
|-1335258 /bin/bash /path/to/application/myapplication start p1
|-1336794 sudo -u admin -i python /path/to/application/myapplication.py start p1
|-1336795 logger
|-1336802 -bash --login -c python \/path\/to\/application/myapplication\.py start p1
`-1336830 sleep 30
* myapplication.service - my application service for p1.
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: activating (start) since Fri 2022-03-25 14:48:27 UTC; 56s ago
Cntrl PID: 1335258 (myapplication)
Tasks: 5 (limit: 9505)
Memory: 3.3M
CPU: 1.444s
CGroup: /system.slice/system-myapplication.slice/[email protected]
|-1335258 /bin/bash /path/to/application/myapplication start p1
|-1336794 sudo -u admin -i python /path/to/application/myapplication.py start
|-1336795 logger
|-1336802 -bash --login -c python \/path\/to\/application/myapplication\.py start p1
`-1336919 sleep 30
* myapplication.service - my application service for p1.
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: activating (start) since Fri 2022-03-25 14:48:27 UTC; 1min 26s ago
Cntrl PID: 1335258 (myapplication)
Tasks: 5 (limit: 9505)
Memory: 3.3M
CPU: 1.447s
CGroup: /system.slice/system-myapplication.slice/[email protected]
|-1335258 /bin/bash /path/to/application/myapplication start p1
|-1336794 sudo -u admin -i python /path/to/application/myapplication.py start p1
|-1336795 logger
|-1336802 -bash --login -c python \/path\/to\/application/myapplication\.py start p1
`-1336998 sleep 30
* myapplication.service - my application service for p1.
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-03-25 14:49:58 UTC; 25s ago
Process: 1337069 ExecStart=/path/to/application/myapplication start (code=exited, status=0/SUCCESS)
Main PID: 1337603 (python)
Tasks: 6 (limit: 9505)
Memory: 7.2M
CPU: 1.541s
CGroup: /system.slice/system-myapplication.slice/[email protected]
|-1337603 python /path/to/application/myapplication.py start p1
|-1337659 /bin/sh -c sudo timeout 15 sudo tcpdump -n -i lo udp port 1234 2> /tmp/capture.txt > /dev/null
|-1337660 sudo timeout 15 sudo tcpdump -n -i lo udp port 1234
|-1337662 timeout 15 sudo tcpdump -n -i lo udp port 1234
|-1337663 sudo tcpdump -n -i lo udp port 6343
`-1337664 tcpdump -n -i lo udp port 6343
我的单元文件没有任何重启延迟
[Unit]
Description=my application service for %i.
[Service]
Type=forking
ExecStart=/path/to/application/myapplication start
ExecStop=/path/to/application/myapplication stop
ExecReload=/path/to/application/myapplication restart
Restart=always
[Install]
WantedBy=multi-user.target
为什么会出现这种延迟,因为它不是定期发生的,有时会发生,有时不会?为什么睡眠的 PID 会改变?最初的想法是,这是尝试重新启动后的新睡眠,但查看输出,status
没有重新启动,Active: activating (start) ...
时间保持不变,直到服务重新启动。
我现在已经做了一些操作,我认为这可能是因为当我将它分离出来时,我将kill
命令作为单行运行kill -9 <p1-PID> <p2-PID> <p3-PID>
kill -9 <p1-PID>
kill -9 <p2-PID>
kill -9 <p3-PID>
我不会为了服务而睡 30 个小时。仍然需要更多的测试来确定,但现在看起来就是这样。
但我还是很好奇为什么sleep 30
会出现?
答案1
您的服务包含Type=forking
.这意味着你的单位期望你的ExecStart=
命令fork()
然后退出。activating (start)
只要该服务ExecStart=
仍在运行,就会一直存在。当ExecStart=
结束时,systemd
将选择一个衍生进程(MainPID
)并进入该active (running)
状态。
您的ExecStart=
程序似乎是一个 bash 脚本。这个脚本可能看起来像这样:
#!/bin/bash
sudo -u admin -i python /path/to/application/myapplication.py start p1 | logger &
while /bin/true; do
sleep 30
done
该脚本有一些问题,但您应该感兴趣的部分是sleep 30
最后的部分。您的主进程正在运行,但 systemdactive (running)
在完成之前不会进入该状态sleep 30
。您每次都会看到一个新的 PID,因为新的 PIDsleep 30
不断被调用。
一个表现良好的脚本会创建您的应用程序,然后立即退出。您的脚本可能正在等待应用程序在退出之前已正确启动的反馈,这很好,但它显然没有得到它正在等待的反馈,因此您需要更深入地挖掘以找出原因不是。
但是,我认为您的脚本更有可能在退出之前等待您的应用程序退出。像这样的东西:
python myapplication.py &
PID=$!
while ps | grep -q $PID; do
sleep 30
done
我认为这是因为听起来像是你在kill
ing python
,而不是ExecStart=
剧本。这意味着该装置将一直保留到完成activating (start)
为止sleep 30
。然后它会检查你的 python 应用程序的 PID 是否仍然存在(不是),然后你的脚本才会停止。
该脚本的另一部分让我困扰的是sudo
. sudo
旨在验证交互式用户。它并不是为了验证脚本。相反,更优雅的解决方案是User=admin
在您的服务中使用。
我看到两个解决方案。选项 2 是迄今为止我最喜欢的:
- 编辑
/path/to/application/myapplication
并删除该while
循环。 - 使用简单的服务并完全跳过该脚本。看起来它是为另一个 init 系统编写的(它显式启动自己的记录器,现在不需要),然后修改为在 shell 中调用时阻止。
systemd
为您完成所有这些工作,所以我敢打赌根本不需要该脚本。
[Unit]
Description=my application service for %i.
[Service]
Type=simple
ExecStart=/usr/bin/python3 /path/to/application/myapplication.py %i
User=admin
Restart=always
[Install]
WantedBy=multi-user.target
如果这没有帮助,请发布内容/path/to/application/myapplication