systemd服务依赖启动失败怎么办?After、Requires与Wants按三层关系排查

拆开启动顺序、拉起关系与失败传播
发布于
5

VPS上的systemd服务如果在重启后因数据库、挂载或网络尚未就绪而失败,不能只靠添加一行 After= 解决。After只定义启动顺序,不会自动拉起依赖,也不保证依赖已经健康;RequiresWants定义拉起关系及失败传播,但同样不等于应用层可连接。

排查时要把问题分成三层:谁先启动、谁需要被一起拉起、依赖失败时当前服务是否也应停止。先读实际单元和本次启动日志,再决定使用 AfterWantsRequires、挂载依赖或应用重试。

三个指令分别解决什么

指令 主要作用 常见误解
After= 当两个单元都要启动时,规定本单元排在对方之后 不会自动启动对方,也不等待应用健康
Wants= 建立较弱的拉起关系,依赖失败时当前单元仍可继续 不代表一定按期望顺序,通常还需排序指令
Requires= 建立更强的必要依赖关系,依赖启动失败会影响当前单元 不等于依赖进程启动后业务已经可用

排序和拉起是两件事。常见组合是 Wants=network-online.targetAfter=network-online.target,但目标是否真的代表“公网可用”,取决于发行版网络管理器和对应的wait-online服务。数据库进程进入active也不代表已完成恢复或开始接受连接。

先读取实际生效的依赖图

systemctl status your-app --no-pager
systemctl cat your-app
systemctl show your-app -p After -p Before -p Wants -p Requires
systemctl list-dependencies your-app
systemctl list-dependencies --reverse your-app

systemctl cat会显示软件包单元与drop-in的合并结果,避免只看某一个文件。正向依赖图回答当前服务需要什么,反向图帮助判断修改后会影响哪些消费者。保存输出后再变更配置。

如果服务已经进入failed状态,先记录 Result、退出码和重启次数,不要连续restart刷新现场。频率限制与重启风暴可参考systemd start-limit-hit的恢复顺序

用本次启动日志还原时间线

journalctl -b -u your-app --no-pager
journalctl -b -u your-database --no-pager
systemd-analyze critical-chain your-app
systemd-analyze blame

journalctl -b把结果限定到当前开机,适合排除旧日志干扰。critical-chain展示影响目标单元启动时间的关键链,blame显示单元初始化耗时,但不能单独证明因果关系:一个服务耗时长,未必就是当前失败的根因。

按时间寻找第一条有因果意义的错误,例如挂载不存在、连接被拒绝、环境文件缺失、权限拒绝或名称解析失败。最后出现的“dependency failed”往往只是结果。

网络依赖:online不等于目标服务可访问

需要IP地址和基本路由的服务,可以核对发行版是否正确启用了NetworkManager-wait-online或systemd-networkd-wait-online。但即使 network-online.target 达成,DNS、远端API、数据库或对象存储也可能仍不可用。

对外部网络依赖,应用应有明确的连接超时、指数退避、最大重试和告警,不宜用无限启动等待掩盖故障。systemd负责启动编排,应用健康仍需要应用自己的探测。

挂载依赖:目录存在不代表数据盘已挂上

服务读取独立数据盘时,可使用针对路径的挂载依赖,而不是只写 After=local-fs.target

[Unit]
RequiresMountsFor=/srv/data

修改前先用 findmnt /srv/datalsblk -f确认真实挂载。挂载失败时,空目录可能仍存在,服务甚至会向根分区写出一套新数据。不要因为路径可见就认为依赖已就绪。

数据库依赖:active与ready是两种状态

应用可以通过 After 和适当的拉起关系安排数据库先启动,但数据库还可能进行崩溃恢复、重放日志或等待磁盘。更稳妥的做法是让应用在启动阶段执行有上限的健康重试,或者由专用的准备单元确认只读探测通过。

准备单元必须具备超时和失败退出,不能无限等待;探测也不应执行迁移、创建数据或其他非幂等操作。数据库版本升级和迁移应由独立发布流程控制。

什么时候用Wants,什么时候用Requires

  • 可降级依赖:监控、缓存或可选队列短时不可用时应用仍能提供核心能力,可考虑较弱关系并在应用内降级。
  • 必要依赖:数据盘或本地数据库缺失时启动必然写错位置或损坏数据,可使用更强关系阻止服务继续。
  • 远端服务:不要把远端URL简单伪装成systemd单元依赖;使用超时、重试、断路和告警更合适。
  • 一次性准备任务:用独立oneshot单元时,应明确 RemainAfterExit、幂等性、超时和失败传播。

依赖强度要与业务后果匹配。过强会让一个可选组件拖垮全部服务,过弱则可能让应用在数据盘或数据库未就绪时错误运行。

使用drop-in修改,不直接改软件包文件

本地调整优先创建drop-in:

sudo systemctl edit your-app

保存后检查并加载:

sudo systemd-analyze verify /etc/systemd/system/your-app.service
sudo systemctl daemon-reload
sudo systemctl restart your-app
systemctl status your-app --no-pager

如果主单元位于软件包目录而调整只在drop-in中,verify的路径要按实际情况选择。语法验证只能发现部分配置问题,不能证明数据库、网络和文件权限都正常。

修复后必须做一次受控重启

  1. 在维护窗口记录关机前服务、挂载和任务状态。
  2. 重启后先确认数据盘,再查看数据库和应用的本次启动日志。
  3. 运行 systemd-analyze critical-chain确认排序与预期一致。
  4. 检查应用健康端点、监听端口、数据库连接和队列。
  5. 从外部路径验证反向代理、TLS和无破坏性的关键请求。
  6. 观察超过原故障窗口,确认服务没有继续重启或进入failed。

VPS重启后网站打不开时,可以结合挂载、数据库、容器与反向代理的启动检查重建完整请求路径。只有受控重启后能自动恢复,依赖配置才算真正通过。

结论

systemd依赖故障不能靠堆叠 After 解决。先区分启动顺序、拉起关系和失败传播,再用实际单元、依赖图和本次启动日志定位。对网络、数据库和远端服务,还要补上应用级健康检查、超时和有限重试;修改后通过受控重启验证,而不是只看一次手动启动成功。

常见问题(FAQ)

systemd里的After会自动启动依赖服务吗?
不会。After只规定两个单元都启动时的先后顺序;是否拉起对方需要Wants、Requires或其他依赖关系。
Requires能保证数据库已经可以连接吗?
不能。Requires可建立较强拉起和失败关系,但数据库进程active时仍可能处于恢复阶段,需要应用级健康检查和有限重试。
network-online.target为什么仍不能访问远端API?
它通常只代表本机网络管理层达到在线条件,不保证DNS、路由、远端服务或应用协议都可用。远端依赖仍要设置超时、重试和告警。
systemd依赖修好后怎样确认不会再次失败?
在维护窗口受控重启,核对挂载、数据库、应用日志和critical-chain,再从本机与外部完成健康和关键路径验证。

本文由作者原创/授权发布于极跃圈(jiyueip.com)未经许可,禁止转载。题图来自Unsplash,基于CC0协议。

声明:极跃圈(JIYUEIP.com)内网友所发表的所有内容及言论仅代表其本人,并不反映任何极跃圈(JIYUEIP.com)之意见及观点。

0 讨论
热门最新
总结
暂无总结
0 / 600