### [systemd服务依赖启动失败怎么办?After、Requires与Wants按三层关系排查](https://www.jiyueip.com/article/13352) **Published:** 2026-07-30T04:19:14 **Author:** 斑斓助理 **Excerpt:** VPS上的systemd服务在重启后因依赖未就绪而失败,不能只添加After。本文拆分启动顺序、拉起关系和失败传播,说明怎样用systemctl、journalctl与systemd-analyze定位并验证。 VPS上的systemd服务如果在重启后因数据库、挂载或网络尚未就绪而失败,不能只靠添加一行 `After=` 解决。`After`只定义启动顺序,不会自动拉起依赖,也不保证依赖已经健康;`Requires`和`Wants`定义拉起关系及失败传播,但同样不等于应用层可连接。 排查时要把问题分成三层:谁先启动、谁需要被一起拉起、依赖失败时当前服务是否也应停止。先读实际单元和本次启动日志,再决定使用 `After`、`Wants`、`Requires`、挂载依赖或应用重试。 ## 三个指令分别解决什么 | 指令 | 主要作用 | 常见误解 | | --- | --- | --- | | `After=` | 当两个单元都要启动时,规定本单元排在对方之后 | 不会自动启动对方,也不等待应用健康 | | `Wants=` | 建立较弱的拉起关系,依赖失败时当前单元仍可继续 | 不代表一定按期望顺序,通常还需排序指令 | | `Requires=` | 建立更强的必要依赖关系,依赖启动失败会影响当前单元 | 不等于依赖进程启动后业务已经可用 | 排序和拉起是两件事。常见组合是 `Wants=network-online.target` 加 `After=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的恢复顺序](https://www.jiyueip.com/article/13284)。 ## 用本次启动日志还原时间线 ``` 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/data` 和 `lsblk -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重启后网站打不开时,可以结合[挂载、数据库、容器与反向代理的启动检查](https://www.jiyueip.com/article/13253)重建完整请求路径。只有受控重启后能自动恢复,依赖配置才算真正通过。 ## 结论 systemd依赖故障不能靠堆叠 `After` 解决。先区分启动顺序、拉起关系和失败传播,再用实际单元、依赖图和本次启动日志定位。对网络、数据库和远端服务,还要补上应用级健康检查、超时和有限重试;修改后通过受控重启验证,而不是只看一次手动启动成功。 **Tags:** Linux服务器, VPS, 云服务器, 代理日志, 国内代理IP **Categories:** 行业洞察 ---