Linux 服务启动顺序优化技巧

1次阅读

应使用 wants=network-online.target + after=network-online.target 并启用 systemd-networkd-wait-online.service 或 networkmanager-wait-online.service;依赖 nginx 需用 bindsto+after 并配合 type=notify 或端口轮询;串行启动须用 requires+after 且避免 defaultdependencies=no 破坏依赖链;排查卡住需检查逆向依赖、拼写错误及执行 daemon-reload。

Linux 服务启动顺序优化技巧

systemd 服务启动依赖怎么写才不卡住 boot

多数人加 After=network.target 就以为网络就绪了,结果服务启动时 curl 还连不上外网——因为 network.target 只表示“网络服务已启动”,不保证 IP 分配完成或 DNS 可用。

真正要等网络就绪,得组合用:

  • Wants=network-online.target + After=network-online.target(推荐)
  • 确保 systemd-networkd-wait-online.service 已启用(否则 network-online.target 永远不就绪)
  • 若用 NetworkManager,需启用 NetworkManager-wait-online.service

漏掉 wait-online 服务,network-online.target 会超时后直接进入 active 状态,看似成功,实则不可靠。

自定义服务想比 nginx 先启动,但总失败

直接写 After=nginx.service 不起作用——因为 nginx 默认是 Type=forking,systemd 只等主进程 fork 后就认为它“启动完成”,此时 worker 进程可能还没 bind 端口。

正确做法分两步:

  • 在你的服务 unit 文件里加:BindsTo=nginx.service + After=nginx.service(强制依赖顺序)
  • 同时让 nginx 显式通知就绪:在 [Service] 段加 Type=notifyExecStartPost=/bin/systemctl notify --ready $MAINPID(需 nginx 编译时带 systemd 支持)
  • 或者更简单:改用 ExecStartPre=/usr/bin/sh -c 'while ! ss -tln | grep :80; do sleep 0.5; done' 做端口轮询(适合临时调试)

硬写 After 而不确认目标服务真实就绪状态,等于没设依赖。

多个服务要串行启动,但用了 Wants 却并行了

Wants= 是弱依赖,只影响启动时机,不阻塞;真正要串行,必须用 Requires= + After=,且目标服务不能设 DefaultDependencies=no

常见翻车点:

  • 自己写的 service 文件里写了 DefaultDependencies=no,却忘了手动补上 Before=multi-user.target 或其它基础 target,导致它被丢到启动末尾甚至不启动
  • 两个服务互相 Wants,形成隐式循环,systemd 会静默忽略部分依赖
  • Conflicts= 代替串行逻辑(比如 A 和 B 不能共存),结果误以为它能控制顺序

串行不是靠“希望它先”,而是靠 Requires 建立强依赖链,并确保整条链上每个单元都参与默认依赖图。

服务启动慢,但 systemctl status 看不出哪卡住

systemctl status myapp.service 显示 activating (start) 卡住,不代表代码慢——可能是 systemd 在等某个 target 就绪,而那个 target 因依赖缺失一直挂起。

排查三步法:

  • 运行 systemctl list-dependencies --reverse --all myapp.service,看它等哪些东西
  • systemctl show myapp.service | grep -E "(After|Before|Wants|Requires)" 检查显式依赖项是否拼写错误(比如写成 nginx.serivce
  • 开 debug 日志:systemctl start myapp.service && journalctl -u myapp.service -o cat -f,重点看最后一行是不是 “Started …” 还是停在 “Starting …”

最常被忽略的是:自定义 service 文件放在 /etc/systemd/system/ 下,但忘记运行 systemctl daemon-reload,导致所有依赖配置全是旧的。

text=ZqhQzanResources