systemd service Restart=always 为什么导致失败循环
来源:17golang原创
时间:2026-09-12 12:04:51 167浏览 收藏
把 Restart=always 写进 service 后,进程一退出就被再次拉起;如果程序本身每次启动都立刻失败,就会看到“启动—退出—再启动”的循环。它并不代表 systemd 能修复应用的根因。更准确的理解是:Restart=always 决定“退出后是否尝试重启”,RestartSec= 决定“隔多久再试”,而 StartLimitIntervalSec= 与 StartLimitBurst= 决定“时间窗口内最多允许多少次启动”。
官方资料:https://github.com/systemd/systemd/blob/main/man/systemd.service.xml
- 先看
Result、ExecMainStatus和 journal,再改 Restart 参数。 - 长期运行的守护进程通常优先用
Restart=on-failure,避免正常退出也被拉起。 - 启动限流触发后,必须修复真实退出原因,再用
reset-failed和一次受控启动复查。
出现这类循环的核心原因大多是进程自身启动时就触发了前置错误,加上 systemd 的重启策略没加边界限制,每次刚拉起立刻报错退出,被规则再次触发重启,最终形成无限失败重启的闭环。
先分清 Restart=always 和启动限流各管什么
systemd 把服务重启拆成两个判断。服务进程退出、被信号终止或启动超时后,Restart=always 会把它纳入自动重启;但每次重启仍然是一次新的启动尝试,受到 unit 的启动速率限制。于是,一个立即退出的二进制会快速消耗启动次数,最后出现 Start request repeated too quickly,服务进入失败状态。
这也是为什么单纯把 Restart=always 改得更“强”通常没有用:它只会让 systemd 更积极地重复同一个错误。建议先把等待时间和上限写清楚:
[Unit] Description=Example worker service # 只描述启动顺序;依赖失败仍要回到对应日志定位 After=network-online.target Wants=network-online.target StartLimitIntervalSec=60s StartLimitBurst=3 [Service] Type=simple ExecStart=/opt/example/bin/worker --config /etc/example/worker.yaml # 守护进程异常退出时重启,正常退出不强行拉起 Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target
StartLimitIntervalSec 和 StartLimitBurst 放在 [Unit];Restart 和 RestartSec 放在 [Service]。如果这个程序是一次性任务,正常退出本来就是成功结果,不应拿 Restart=always 把它变成长驻服务。

用退出码和日志找到真正的失败原因
看到循环时不要先执行多次 restart 把现场冲掉。先保存状态与最近日志:
# 读取当前状态、主进程退出码和最近一段日志 sudo systemctl status example-worker.service --no-pager sudo systemctl show example-worker.service \ -p Result -p ExecMainCode -p ExecMainStatus -p NRestarts sudo journalctl -u example-worker.service -b -n 80 --no-pager
如果 Result=exit-code、ExecMainStatus=1,优先检查配置文件、工作目录、权限和环境变量;如果是 status=203/EXEC,重点看 ExecStart 路径、执行权限和解释器;如果日志只剩“repeated too quickly”,说明限流是结果,不是最初的根因。NRestarts 可以帮助确认是否真的发生了多次自动拉起。
| 证据 | 通常说明 | 下一步 |
|---|---|---|
ExecMainStatus=1 | 程序主动以非零码退出 | 看应用日志、配置和参数 |
203/EXEC | 执行文件或执行方式有问题 | 检查路径、权限、shebang |
Start request repeated too quickly | 启动速率限制已触发 | 先修复前两项,再复位失败状态 |

依赖关系会放大问题,但不会替代根因
After=network-online.target 只表达排序,不能保证网络服务已经满足应用的业务条件;Wants= 会在当前服务启动时顺带拉起目标,但目标失败不一定让本服务失败;Requires= 的失败影响更强,依赖停止时本服务也可能被停止。排查时应同时看依赖树:
# 查看 unit 的依赖与排序关系,避免把依赖链误认为重启根因 sudo systemctl list-dependencies example-worker.service sudo systemctl cat example-worker.service sudo systemd-analyze verify /etc/systemd/system/example-worker.service
如果服务依赖了一个同样会失败的 unit,先修复被依赖方;如果配置里存在相互触发的 Wants= 或外部 watchdog,也要确认是谁真正发起了下一次启动。不要用增加 StartLimitBurst 来掩盖依赖链上的配置错误。
修改后怎样安全恢复并确认没有再循环
确认配置已保存后,先让 PID 1 重新读取 unit,再清掉“因限流留下的失败状态”,最后只启动一次:
# 重新载入 unit,清除失败标记,然后进行一次受控启动 sudo systemctl daemon-reload sudo systemctl reset-failed example-worker.service sudo systemctl start example-worker.service sudo systemctl status example-worker.service --no-pager sudo journalctl -u example-worker.service -b -n 40 --no-pager
成功标准不是“命令返回成功”这么简单,而是服务保持 active (running),NRestarts 不再持续增加,日志中没有新的退出与限流提示。如果程序确实会因临时依赖失败而退出,可以保留 Restart=on-failure,把 RestartSec 调到足以等待依赖恢复的值;不要无限放大限流窗口,让错误变成高频重启。
相关问题
Restart=always 和 Restart=on-failure 有什么区别?
always 连正常退出也会尝试重启;on-failure 主要针对非零退出、异常信号和超时。长时间运行的服务通常先选后者。
为什么 Restart=always 仍然不重启?
可能已触发启动速率限制,也可能是手动停止、条件判断未满足或 unit 根本没有成功进入可重启的服务状态。先看 journal 和 systemctl show,不要只看配置文件。
改完 service 文件为什么没有生效?
unit 文件变更需要 systemctl daemon-reload;它只重新载入配置,不等于已经启动新进程。之后再按需执行 reset-failed 和一次 start。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
435 收藏
-
297 收藏
-
216 收藏
-
285 收藏
-
275 收藏
-
文章 · linux | 23小时前 | Linux · 文件系统 · 挂载 · 运维排障 · 工作目录 bind mount Linux mount --bind umount target is busy EBUSY476 收藏
-
244 收藏
-
115 收藏
-
429 收藏
-
384 收藏
-
207 收藏
-
255 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习