本质是错误未解决而重启策略持续触发,需通过journal日志识别循环模式、检查restart与startlimit配置、定位依赖/资源/oom/启动逻辑四类根因。

服务在 systemd 下反复启动又退出,形成“Started → Stopped → Started”循环,本质是错误未解决而重启策略持续触发。关键不是压制重启,而是让循环暴露原始失败点。
看 journal 日志识别循环模式
运行 journalctl -u your-service.service -n 100 -o cat --no-pager,重点找重复出现的启动段落:
- 每段以
Started xxx开头,紧接几行日志,结尾是Stopped xxx或Failed with result 'exit-code' - 若看到连续多段“Started → main process exited, code=exited, status=1”,说明服务每次都在同一环节失败
- 加
-o cat是为了去掉时间戳和优先级前缀,避免干扰判断;--no-pager防止分页遮挡上下文
查 Restart 策略是否掩盖了首次失败
systemd 默认的 Restart=on-failure 或 Restart=always 会让服务刚退出就拉起,导致 systemctl status 显示 “active (running)” —— 实际只是刚被重启的假象。
监控 Victron Energy 电力系统,生成包含电池状态、光伏发电量和活动警报的精美每日邮件报告。集成 Vic...
- 运行 systemctl show your-service.service | grep -E "(Restart|StartLimit)" 查当前配置
- 重点关注
StartLimitIntervalSec=60和StartLimitBurst=3:一旦单位时间内失败超限,systemd 会彻底停手并标记为start-limit-hit,此时systemctl status才真正显示 failed,原始错误才浮出水面 - 临时调试可改
StartLimitBurst=1,让第一次失败就卡住,方便抓取完整日志
定位真实失败原因的四个关键方向
无限重启背后,常见根因集中在这四类:
-
依赖未就绪:服务启动时尝试连接数据库、Redis 或远程 API,但依赖服务尚未启动或网络未通。用
After=xxx.service只控顺序,不保状态;应配合BindsTo=xxx.service,让依赖挂掉时本服务也自动终止,避免盲目重试 -
资源冲突或权限不足:端口被占、配置文件不可读、工作目录不存在、用户无权访问证书路径。手动切换到服务用户(如
sudo -u myuser -s)执行ExecStart命令,能直接复现静默失败 -
OOM Killer 干预:日志里出现
status=137或Killed by signal SIGKILL,大概率是内存耗尽被内核强杀。运行dmesg -T | grep -i "killed process"确认;检查MemoryMax=是否设限,或容器环境 cgroup 内存上限是否过低 -
进程启动即退出,未真正驻留:比如脚本缺少
exec导致 fork 后父进程退出,systemd 误判为启动完成;或 Java/Python 服务未加-Dspring.profiles.active=prod等必要参数,初始化失败后立刻 exit
验证与收尾
改完配置后,按顺序执行:
- sudo systemctl daemon-reload —— 重载 unit 文件
- sudo systemctl reset-failed your-service.service —— 清除失败状态,避免旧锁影响
- sudo systemctl start your-service.service —— 单次启动,观察是否还进循环
- 再跑
journalctl -u your-service.service -f实时盯日志,直到看到第一段失败的完整堆栈或错误行










