跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Linux 服务启动顺序如何控制?

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

相关文章