提升系统的启动性能可以缩短启动等待时长,还能学习系统文件和脚本见交互的方式。本文整合了数种提升 Arch Linux 启动性能的方式。
启动过程分析
使用 systemd-analyze
systemd 提供了一个名为 systemd-analyze
的工具,可用于显示有关启动过程的计时细节, 包括一个显示各单元等待其依赖项的 svg 图。您可以看到哪些单元文件导致启动过程减慢, 然后可以相应地优化系统.
要查看启动时在内核/用户空间中消耗的时间, 只需使用:
$ systemd-analyze
按照耗费时间顺序,列出启动各个单元耗费的时间:
$ systemd-analyze blame
在启动过程的一些时刻,需要特定的单元成功启动了才能继续。要查看在启动链中哪些单元处于这些关键点,可以执行:
$ systemd-analyze critical-chain
类似于 Bootchart,还可以生成 SVG 形式的启动流程图:
$ systemd-analyze plot > plot.svg
更多信息请参考 systemd-analyze(1)。
使用 bootchart2
你还可以使用 Bootchart2 将启动流程可视化。
编译自定义内核
使用自定义内核可以减少启动时间和内存占用,但由于 Linux 内核的模块化特性以及 64 位架构的逐渐标准化,这些好处可能没有预期的那么大。具体信息请参考内核#编译。
官方内核的模块默认压缩等级为 ZSTD_CLEVEL=19
,但 SSD 可能更适合使用 ZSTD_CLEVEL=1
。
建议将会用到的存储和文件系统模块嵌入到内核中,以使用 Arch 的启动流程#Running_without_initramfs。
Initramfs
最佳做法是 Arch 的启动流程#Running_without_initramfs。
mkinitcpio 默认使用 base
和 udev
钩子,将它们替换为 systemd
可以提升启动速度,具体细节请参考 Mkinitcpio#常用钩子。如果要替换 fsck
钩子,请参考 Fsck#启动时检查。
与#编译自定义内核类似,initramfs 也可以被精简。最简单的方法是包含 mkinitcpio 的 autodetect
钩子。Booster 可以生成比 mkinitcpio 和 dracut 更小的 initramfs,并使用更快的单二进制文件 init. 参阅 极简 initramfs 或 Booster#Removing modules 以获得更多信息。
取决于你的硬件(处理器和存储速度)不同,由于启动时更快的解压速度通常可以抵消掉从硬盘读取稍大的 initramfs 的负面影响,使用 lz4包 取代默认的 zstd包 压缩算法有可能会更快,具体细节请参考 Mkinitcpio#压缩方式(COMPRESSION)。
选择合适的服务启动方式
systemd 的一个核心功能是 D-Bus 和 socket 激活。多数情况下建议使用该功能,它会使服务只在初次访问时启动,通常来说这是件好事(例如 cups.service
在桌面环境通常没必要开机启动,而启用 cups.socket
会使只在打印时启动服务)。
但如果有个服务(以 upower包 为例)始终会在开机时启动,那尽早将其启动有可能会减少启动耗时,该操作可通过启用 upower.service
达成(前提是已配置了启动文件,多数情况下都是如此)。
这样 systemd 就会尽早启动 UPower,而不会引起 socket 或 D-Bus 激活的竞争。
分批启动
有些硬件使用了分批启动(Staggered spin-up,SSP),会使系统按顺序探测 ATA 接口,从而使硬盘逐个轮流启动,以降低耗电峰值。这会降低启动速度,且由于多数消费级硬件在通电后就会立即启动,因此并没有提供什么优势。执行以下命令可以检查是否启用了分批启动:
# dmesg | grep SSS
无输出表示没有使用该功能。
可以将 libahci.ignore_sss=1
添加到内核参数以禁用该功能。
挂载文件系统
借助 mkinitcpio 的 fsck
钩子,你可以通过在内核命令行中将 ro 改为 rw 来避免对 root 分区进行影响性能的重挂载:一个选择是使用 rootflags=rw,other_mount_options
来设置相关选项。必须从 /etc/fstab
中移除对应的条目,否则 systemd-remount-fs.service
仍会尝试应用这些设置。或者,也可以尝试屏蔽(mask)此服务单元。
如果根文件系统是 Btrfs,就不需要和其他文件系统一样每次启动都进行 fsck
。在这种情况下,可以移除 mkinitcpio 的 fsck 钩子。你也可以选择屏蔽(Mask) systemd-fsck-root.service
,或者使用内核命令行fsck.mode=skip
来告诉根文件系统跳过 fsck
。没有 mkinitcpio 的 fsck 钩子,systemd 仍会使用 systemd-fsck@.service
对任何相关的文件系统进行 fsck。
你也可以移除/etc/fstab
中的 API 文件系统,因为 systemd 会自动挂载它们(列表见 pacman -Ql systemd | grep '\.mount$'
)。用户可能看到从 sysvinit 迁移过来的 /tmp
条目,但你可能已经注意到,从上面的命令可以看出,systemd 已经处理了这个问题。因此,/tmp
条目可以安全地移除。
其他文件系统,比如 /home
或者 EFI 系统分区,可以使用自定义的挂载单元进行挂载。向挂载参数中添加 noauto,x-systemd.automount
会延迟挂载分区,直到首次访问时才进行 fsck 和挂载,从而减少启动过程中需要 fsck 或挂载的文件系统数量,帮助加快启动速度。
- 这将使你的
/home
文件系统类型变成autofs
,默认情况下,locate 会忽略它。自动挂载/home
的加速效果可能不会超过一两秒,具体取决于你的系统,因此这个技巧可能并不值得尝试。 - 如果系统安装在一个 btrfs 子卷中(具体来说:根目录
/
本身是一个子卷),并且/home
是一个独立的文件系统,你可能还需要防止创建一个/home
子卷。可以通过屏蔽home.conf
临时文件来实现:ln -s /dev/null /etc/tmpfiles.d/home.conf
。
精简启动阶段输出信息
对于某些用户,特别是 SSD 用户,TTY 的龟速实际上成为了性能瓶颈,精简输出信息实际上有利于提高性能。具体建议请参考静默启动。
替换启动引导器
替换引导加载程序(例如换成 systemd-boot 这种简单的引导器)可能会减少数秒的启动时间。
在可用的情况下,只使用一个 EFI boot stub 可以进一步降低启动耗时。
内核参数
有些内核参数可以提升启动性能。
如果不需要 systemd-gpt-auto-generator,使用 systemd.gpt_auto=no
可能会减少 0.2~3 秒的启动时长。如果根分区是 Btrfs 且没有使用 initramfs 进行启动,那 systemd-gpt-auto-generator 不会起效[1]。
cryptomgr.notests
会禁用自测试,但效果可能不大。
挂起到内存
减少启动时长的最好方法是完全不用启动,可以考虑转而将系统挂起到内存。