systemd通过After=和Requires=声明依赖关系控制启动顺序,After=仅表示时间先后,Requires=才是硬性前提;漏写Requires=易致服务因依赖失败而异常,应优先修改/etc/下的单元文件并执行daemon-reload。
用
和
控制服务启动先后
systemd 不靠“谁排第几个”决定顺序,而是靠依赖声明。你写
,只表示“我比 network.target 启动得晚”,但不保证 network.target 一定成功;而加了
,就变成硬性前提——如果 network.target 启动失败,你的服务压根不会尝试启动。
常见错误是只写
却漏掉
,结果网络还没通,你的服务就急着连数据库,直接超时失败。反过来,对非关键服务(比如日志轮转),应避免滥用
,改用
降低耦合。
查当前服务的依赖:运行
修改前先备份原文件:
(优先改
下副本)
改完必须执行
,否则
或
都不生效
为什么
不等于“立刻按顺序启动”
只是创建软链接到
,让服务被 multi-user.target 拉起——但它不指定“在哪个时刻启动”,真正顺序由单元文件里的
、
等字段决定。很多人禁用一个服务后发现另一个服务也起不来,其实是后者在单元文件里写了
前者,而非启动脚本里有硬
编码
调用。
检查某服务是否真被启用:
(输出
才算)
确认它是否实际参与了本次启动:
看
行末尾是否带
,且
是
禁用服务用
,不是删文件,也不是改
字段
可视化启动瓶颈:用
找卡点
系统启动慢,不一定是某个服务本身慢,更可能是它前面一堆服务串行堵着。比如
被设为
,但
又等
(默认超时 2 分钟),结果整个数据库启动被拖垮。
Comet AI 浏览器
下载 Comet AI 浏览器,体验由 Perplexity AI 驱动的革命性上网方式。内置 AI 助手可实时总结网页、跨标签页对比信息、自动执行任务。告别繁琐操作,让 AI 成为你的浏览副驾,大幅提升研究与工作效率。支持 Windows、macOS、Android 和 iOS。
下载
生成 SVG 启动时序图:
,用
浏览器
打开就能看到哪段横条最长、哪些服务并行度低
快速定位耗时大户:
列出各服务启动耗时(单位 ms),排第一的未必是问题根源,但值得优先看它的
依赖链
若某服务只需网络“可达”而非“完全在线”,把
改成
,再加
,能跳过等待 DHCP 的长延迟
别碰
—— 它和 systemd 有隐式冲突
很多老教程教你在
里写启动命令,但在 systemd 系统中,这个文件本质是通过
单元来加载的,它默认
,但没声明
任何具体服务。结果就是:你的脚本可能在 MySQL 还没起来时就去连库,或者在 Docker socket 尚未就绪时就执行
,报错
。
替代方案:写一个专用 .service 文件,明确写
和
如果只是想开机跑一条命令,用
(需 systemd v249+)
检查
是否启用:
,Ubuntu 22.04+ 默认已禁用,强行启用反而易出问题
最常被忽略的一点:服务单元文件里写的
是“相对顺序”,不是“绝对时间点”。哪怕你把所有服务都设成
,systemd 仍会按依赖图自动调度并行度——所以别迷信“我把 A 改成 After=B,B 就一定先于 A 启动”,最终顺序还得看整个依赖网如何收敛。
After=Requires=After=network.targetRequires=network.targetAfter=Requires=Requires=Wants=systemctl show nginx.service -p Wants,Requires,Aftersudo cp /usr/lib/systemd/system/nginx.service /etc/systemd/system/nginx.service/etc/sudo systemctl daemon-reloadenablerestartsystemctl enablesystemctl enable/etc/systemd/system/multi-user.target.wants/After=Wants=Requires=systemctl is-enabled servicenameenabledsystemctl status servicenameLoaded:enabledActive:active (running)sudo systemctl disable servicenameWantedBy=systemd-analyze plotpostgresql.serviceAfter=network.targetnetwork.targetsystemd-networkd-wait-online.servicesystemd-analyze plot > boot.svgsystemd-analyze blameAfter=After=network-online.targetAfter=network.targetWants=network.target/etc/rc.local/etc/rc.localrc-local.serviceAfter=multi-user.targetWants=docker runconnection refusedAfter=mysqld.serviceRequires=mysqld.servicesystemd-run --on-boot --scope --unit=my-onboot-script /path/to/script.shrc-local.servicesystemctl is-enabled rc-localAfter=After=multi-user.target