Fedora 的开机速度受多种因素影响,其中服务启动阶段往往占据主要时间。systemd 虽然默认并行启动无依赖关系的服务,但许多单元因为不合理的依赖配置、错误的启动类型或未被使用的常驻服务而拖慢整体流程。优化并行启动的目标不是盲目关闭服务,而是让可以同时执行的服务真正并行,同时减少关键路径上的等待时间。下面从启动依赖、分析工具和具体配置调整三个方面展开。

理解systemd的并行启动与依赖
systemd 在系统启动时会解析所有已启用的单元,并构建依赖图。只有当单元的依赖条件满足后,它才会进入启动队列。依赖关系中的 After 和 Before 只影响顺序,不会强制要求另一个单元成功启动;而 Requires、Wants、Requisite 等则表达强弱不等的启动依赖。理解这一点非常重要:如果两个服务只是先后顺序关系,即使写成 After,它们也不会完全串行,第二个服务会在第一个服务启动完成后立即开始,而不是等待第一个服务的所有进程完全就绪。真正造成串行等待的,通常是单元类型为 forking 或 dbus 的服务,它们在启动过程中会阻塞 systemd 直到父进程退出或总线名称出现。
举例来说,常见的网络管理服务 NetworkManager 与日志服务 rsyslog 之间若没有显式依赖,systemd 会尽量同时启动它们。但实际环境中,自定义服务可能通过 After=network.target 和 Wants=network.target 绑定到网络目标,如果没有正确理解 network.target 只代表网络管理栈启动完成、不代表链路可用,就可能错误地让本地服务等待过久。单元文件中的依赖越少、越精确,并行度就越高。
[Unit] Description=My Custom Service After=network.target Wants=network.target [Service] Type=simple ExecStart=/usr/local/bin/my-service Restart=on-failure [Install] WantedBy=multi-user.target
这是一个典型的单元片段。把 Type 设为 simple 可以让 systemd 在 fork 之后立即认为服务已启动,从而释放后续单元的执行机会。如果服务本身不支持前台运行而必须使用 forking 类型,那么就难以避免阻塞,需要考虑改造服务或改用其他激活方式。
使用systemd-analyze定位并行瓶颈
要优化并行启动,首先需要知道当前的启动时间花在哪里。Fedora 自带 systemd-analyze 工具,可以显示总启动耗时、各单元耗时排序以及关键依赖链。最常用的命令是 systemd-analyze blame,它会按初始化耗时从长到短列出所有被启动的单元。需要注意的是,blame 输出的时间不是纯等待时间,而是该单元自身初始化耗时,不包含它等待其他单元的时间。因此看 blame 可以快速发现哪些服务自身启动慢。
systemd-analyze blame
输出类似下面这样,部分服务可能因为等待磁盘 I/O 而显示较长时间:
3.125s NetworkManager-wait-online.service 1.876s dnf-makecache.service 1.203s systemd-journal-flush.service 800ms udisks2.service 650ms systemd-resolved.service
另一个重要命令是 systemd-analyze critical-chain,它可以显示从启动开始到某个目标(默认图形界面)的关键依赖链。这条链上的服务如果有一个慢,就会拖累最终进入桌面的时间。例如输出可能显示 multi-user.target 依赖 network-online.target,而 network-online.target 又依赖 NetworkManager-wait-online.service,那么优化 NetworkManager-wait-online 或去掉对 network-online.target 的依赖就能缩短关键路径。
systemd-analyze critical-chain
还可以用 systemd-analyze plot > boot.svg 生成完整的启动时序图,直观查看哪些服务并行、哪些串行。这个图对发现“假并行”现象很有帮助:有时多个服务虽然在依赖图中没有顺序关系,但由于都请求了同一个互斥资源(如同一块慢速磁盘或 CPU),实际启动会接近串行。
优化并行启动的具体方法
第一种最直接的方法是禁用不需要的服务。Fedora 默认会启用一些通用服务,例如蓝牙、打印、虚拟机支持等,如果硬件或使用场景不涉及,就可以安全关闭。使用 systemctl list-unit-files --type=service --state=enabled 查看所有开机自启服务,结合 systemctl disable 与 systemctl mask 进行控制。禁用服务时要留意 Fedora 预设(preset)策略,有些服务在软件包更新后可能被重新启用,可以使用 systemctl preset 或配置 preset 文件来固定状态。
第二种方法是调整单元类型。对于支持前台运行的服务,将 Type=forking 改为 Type=simple 能显著减少启动阻塞。对于支持 sd_notify 的服务,使用 Type=notify 可以在服务完成初始化后立即通知 systemd,比 forking 更精确且不必等父进程退出。修改后执行 systemctl daemon-reload 并重启服务验证。需要注意的是,并非所有服务都能安全修改类型,需确认服务进程不会提前退出导致 systemd 误判。
第三种方法是拆分大型服务。有些服务的启动脚本会在 ExecStartPre 中执行大量初始化命令,例如等待网络、生成缓存、检查数据库连接等,这些串行步骤会拖慢关键路径。将其拆分为多个独立单元或使用 oneshot 单元按需触发,可以让不依赖这些步骤的服务先行启动。也可以把耗时的初始化移到 ExecStartPost 或通过 timer 延迟到空闲时执行。
第四种方法是使用 socket 激活。对于只在需要时提供服务的后台进程,例如 sshd、打印服务、数据库等,可以创建 .socket 单元让 systemd 在收到连接请求时才启动对应服务。这样开机阶段完全不消耗时间,只有在首次使用时才产生延迟。Fedora 中一些服务默认已使用 socket 激活,例如 Cockpit。若要改造自定义服务,可参考 /usr/lib/systemd/system/sshd.socket 的结构,创建同名 .socket 文件并启用。
[Socket] ListenStream=22 Accept=no [Install] WantedBy=sockets.target
需要搭配对应的 .service 文件,服务单元不再设置 WantedBy 到 multi-user.target,而是由 socket 自动触发。这样服务在开机时不会启动,systemd 并行压力进一步降低。
进阶优化与风险控制
并行启动虽然能缩短时间,但也可能带来资源争抢。当大量服务同时启动时,CPU 核心数、内存带宽和磁盘 I/O 会成为新的瓶颈。此时可以通过 systemd 的资源控制选项限制某些服务的并行度,例如在服务单元中添加 CPUSchedulingPolicy、IOSchedulingClass 或 Nice 值,让关键服务优先获得资源。不过这些措施更多是缓解资源竞争,并非直接提升并行度,需结合具体硬件调整。
[Service] CPUSchedulingPolicy=idle IOSchedulingClass=idle Nice=19
另一个容易忽略的方面是安装的第三方软件和容器工具。某些软件在安装时会向 systemd 注册自己的启动单元,并设置过于保守的依赖关系。定期检查 /etc/systemd/system 下自定义单元和 /usr/lib/systemd/system 下软件提供的单元,如果发现不合理的 After= 或 Requires=,可以用 drop-in 覆盖片段而不是直接修改原文件。例如创建 /etc/systemd/system/某服务.service.d/override.conf,只调整需要的项,这样系统更新时不会丢失修改。
systemctl edit 某服务.service
最后,任何优化都应在测试环境或可回滚的快照下进行。建议每次只改动一类配置,改完后重启并测量 systemd-analyze 的结果,确认关键路径确实缩短且系统功能正常。另外,SSD 相比机械硬盘在并行随机读写上优势明显,如果硬件仍是机械硬盘,软件层面的并行优化收益会受限,此时升级硬盘可能是更有效的方案。
Fedora并行启动服务优化systemd修改时间:2026-09-22 01:15:53