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 分钟),结果整个数据库启动被拖垮。
1、请上传下载到的淘宝客系统安装包并上传到空间根目录中进行解压,解压后将网站文件移动到根目录的位置,然后访问 /install 进行安装。您也可以在本地解压,并以二进制方式将程序上传至您的网站空间。 2、同意启科网络电子商务系统安装协议进入下一步。 3、如果系统检测环境通过,则会提示输入您的数据库服务器地址(一般为本机,即127.0.0.1或者localhost)、数据库账号、数据库密码、数据库名
- 生成 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 启动”,最终顺序还得看整个依赖网如何收敛。









