systemd服务启动顺序由显式依赖声明(如after=、requires=、wants=)决定,而非文件名或目录顺序;需结合依赖字段与systemd-analyze等工具验证实际启动时序。

systemd 服务启动顺序由依赖关系决定,不是按字母或时间排序
systemd 不像 SysVinit 那样靠 rc3.d 目录里 S01foo、S02bar 的数字前缀控制顺序。它用的是声明式依赖:哪个服务先启动,取决于它声明了 After=、Before=、Wants=、Requires= 等字段指向谁。直接看文件名或列表顺序毫无意义。
想确认某个服务的实际启动时机,不能靠 ls /etc/systemd/system/multi-user.target.wants/,而要看它的单元定义:
- 运行
systemctl cat <service>.service</service>查看原始 unit 文件内容 - 重点关注
[Unit]段里的After=和Before=(例如After=network.target表示等网络就绪后才启动) - 注意
[Install]段的WantedBy=(如multi-user.target),这决定了它被哪个目标“拉起”
/etc/rc.local 的执行时机是明确的:所有 systemd 服务之后、登录前
/etc/rc.local 在绝大多数 systemd 系统中仍被保留,且默认作为 rc-local.service 运行。它的实际位置和行为由 systemctl cat rc-local.service 决定——通常会显示它设置了 After=multi-user.target,并 WantedBy=multi-user.target。
这意味着:/etc/rc.local 一定在所有标记为 multi-user.target 的服务(即常规后台服务)全部启动完毕后才执行,但早于 getty@.service(登录终端)启动。它是最可靠的“最后统一入口”,适合放那些必须等网络、数据库、文件系统都 ready 后才跑的命令。
注意两点:
- 该文件必须有可执行权限:
chmod +x /etc/rc.local,否则 systemd 会静默跳过 - systemd 默认不启用它,需手动启用:
systemctl enable rc-local.service - 某些发行版(如较新 Ubuntu)默认禁用
rc-local,启用前先检查状态:systemctl status rc-local.service
SysVinit 风格脚本的执行顺序仍在 /etc/rc.d/rcN.d 中可见
如果你的系统还混用 SysVinit 脚本(比如 CentOS 7 或某些定制环境),/etc/rc.d/rc3.d/(或 rc5.d)目录下的符号链接就是真实执行顺序的体现。
这些链接名格式固定:Sxx<service></service> 或 Kxx<service></service>,其中 xx 是两位数字,决定加载/关闭顺序:
-
S01sysstat比S99local先执行 - 所有
S*按数字升序依次调用/etc/init.d/<service> start</service> - 数字只是排序依据,不代表毫秒级时序;同一数字下多个服务启动顺序不确定
- 不要手动改数字来“抢顺序”,应优先通过
chkconfig --level 3 myscript on注册,再由chkconfig自动分配合理编号
真正要排查启动慢或失败,得看 journal 时间线
光知道“谁在谁后面”不够,得看“谁花了多久、卡在哪”。systemd-analyze 系列命令才是定位顺序问题的核心工具:
-
systemd-analyze blame:列出所有已启动 unit 的耗时,从长到短排,一眼看出拖慢启动的罪魁 -
systemd-analyze critical-chain:展示从default.target回溯最长依赖链,比如nginx.service → network-online.target → NetworkManager-wait-online.service,说明 nginx 启动延迟可能源于网络等待超时 -
systemd-analyze plot > boot.svg:生成 SVG 时间线图,直观看到各服务并发/串行关系
记住:启动顺序不是静态列表,而是动态依赖图。一个服务是否“晚启动”,往往不是它自己慢,而是它等的上游服务没按时就绪——比如 docker.service 卡住,常是因为 containerd.service 启动失败,而后者又依赖 system.slice 下某个挂载点。











