systemd 教程 / 启动分析与优化
启动分析与优化
systemd 提供了丰富的工具来分析和优化系统启动时间。通过理解启动流程和关键路径,可以显著减少系统从开机到可用的等待时间。
1. systemd-analyze 命令
1.1 基本启动时间分析
# 查看启动各阶段耗时
systemd-analyze
# 输出示例:
# Startup finished in 1.234s (firmware) + 5.678s (loader) + 2.345s (kernel) + 12.567s (initrd) + 8.901s (userspace) = 30.725s
# graphical.target reached after 8.890s in userspace
1.2 systemd-analyze blame
blame 列出每个服务的启动时间,按耗时从长到短排序:
# 查看所有服务启动时间
systemd-analyze blame
# 输出示例:
# 15.234s NetworkManager-wait-online.service
# 8.567s plymouth-quit-wait.service
# 5.123s firewalld.service
# 3.456s cups.service
# 2.789s avahi-daemon.service
# 1.234s systemd-udev-settle.service
# 890ms initrd-parse-etc.service
# 567ms lvm2-monitor.service
# 按服务类型过滤
systemd-analyze blame --type=service
# 只看用户空间服务
systemd-analyze blame --user
# JSON 格式输出
systemd-analyze blame --json=pretty
1.3 systemd-analyze critical-chain
critical-chain 显示关键路径——决定启动总时间的服务链:
# 查看默认目标的关键路径
systemd-analyze critical-chain
# 输出示例:
# The time after the unit is active or started is printed after the "@" character.
# The time the unit takes to start is printed after the "+" character.
#
# graphical.target @8.890s
# └─multi-user.target @8.889s
# └─cups.service @5.433s +3.456s
# └─network.target @5.432s
# └─NetworkManager.service @2.891s +2.540s
# └─basic.target @2.890s
# └─sockets.target @2.889s
# └─dbus.socket @2.889s
# 指定目标查看
systemd-analyze critical-chain multi-user.target
# 查看指定服务的关键路径
systemd-analyze critical-chain nginx.service
1.4 systemd-analyze plot
生成 SVG 启动时序图:
# 生成 SVG 图
systemd-analyze plot > boot.svg
# 在浏览器中查看
xdg-open boot.svg # 桌面环境
# 或
python3 -m http.server 8080 --directory /tmp # 服务器
💡 提示:SVG 图是分析启动并行度的最佳工具,可以直观看到服务之间的依赖关系和等待时间。
1.5 systemd-analyze dump
输出完整的 systemd 内部状态:
# 输出到终端
systemd-analyze dump
# 重定向到文件(输出很长)
systemd-analyze dump > /tmp/systemd-dump.txt
# 过滤特定服务
systemd-analyze dump | grep -A 20 "nginx.service"
2. 启动时间分析
2.1 启动阶段详解
| 阶段 | 说明 | 典型耗时 |
|---|---|---|
| firmware | UEFI/BIOS 初始化 | 1-10s |
| loader | 引导加载程序(GRUB) | 1-5s |
| kernel | 内核加载和初始化 | 1-5s |
| initrd | 初始内存盘 | 2-15s |
| userspace | 用户空间服务 | 5-30s |
2.2 内核启动时间分析
# 查看内核启动时间
systemd-analyze time
# 查看内核日志中的时间戳
dmesg | less
# 查看内核初始化耗时
dmesg | grep -i "initcall" | sort -k3 -n -r | head -20
2.3 initrd 启动时间分析
# 查看 initrd 阶段的服务
systemd-analyze blame --firmware-setup
# 分析 initrd 内容
lsinitrd /boot/initramfs-$(uname -r).img | less
# 重建 initrd(优化后)
sudo dracut --force --hostonly
3. 关键路径分析
3.1 理解依赖关系
# 查看服务依赖树
systemd-analyze dot nginx.service
# 生成依赖图
systemd-analyze dot --to-pattern='*.target' | dot -Tsvg > deps.svg
# 查看反向依赖
systemctl list-dependencies --reverse nginx.service
3.2 依赖优化策略
| 策略 | 方法 | 适用场景 |
|---|---|---|
| 延迟启动 | Type=oneshot + RemainAfterExit=yes | 非关键服务 |
| 弱依赖 | Wants= 替代 Requires= | 非必需依赖 |
| 并行化 | 减少 After= 约束 | 无依赖关系的服务 |
| Socket 激活 | 使用 socket 协议 | 有客户端的服务 |
4. 服务并行启动优化
4.1 并行化配置
# /etc/systemd/system.conf
[Manager]
DefaultDependencies=yes
DefaultTasksMax=4096
4.2 减少不必要的 After 依赖
# 优化前:串行启动
[Unit]
Description=My Service
After=network.target mysql.service redis.service
# 优化后:只在真正需要时添加 After
[Unit]
Description=My Service
After=network.target
Wants=mysql.service redis.service
4.3 Socket 激活
使用 socket 激活可以解耦服务启动顺序:
# myapp.socket
[Unit]
Description=My App Socket
[Socket]
ListenStream=8080
[Install]
WantedBy=sockets.target
# myapp.service
[Unit]
Description=My App
Requires=myapp.socket
[Service]
ExecStart=/usr/bin/myapp --socket=fd
5. 启动超时处理
5.1 超时配置
# /etc/systemd/system.conf
[Manager]
# 默认启动超时(秒)
DefaultTimeoutStartSec=90s
# 默认停止超时
DefaultTimeoutStopSec=90s
# 设备超时
DefaultDeviceTimeoutSec=90s
5.2 服务级超时
[Service]
# 设置较长超时
TimeoutStartSec=300
# 禁用超时(不推荐)
TimeoutStartSec=infinity
5.3 超时后行为
[Service]
# 超时后发送 SIGTERM
TimeoutStopSec=30
# 超时后强制 kill
KillMode=mixed
KillSignal=SIGTERM
FinalKillSignal=SIGKILL
⚠️ 注意:将超时设置过短会导致服务启动失败,设置过长会影响启动速度。建议根据服务实际需求设置。
6. initramfs 优化
6.1 分析 initramfs 大小
# 查看 initramfs 内容
lsinitrd /boot/initramfs-$(uname -r).img | wc -l
# 查看大小
ls -lh /boot/initramfs-$(uname -r).img
# 查看占用空间最多的文件
lsinitrd /boot/initramfs-$(uname -r).img | sort -k5 -n -r | head -20
6.2 优化 initramfs
# 使用 hostonly 模式(仅包含当前硬件所需模块)
sudo dracut --force --hostonly
# 排除不需要的模块
sudo dracut --force --hostonly --omit "network iscsi"
# 压缩算法优化
sudo dracut --force --hostonly --compress="xz -9 --check=crc32"
6.3 Dracut 配置
# /etc/dracut.conf.d/optimize.conf
# 仅包含当前硬件驱动
hostonly="yes"
# 排除的模块
omit_dracutmodules+=" network iscsi fcoe "
# 压缩算法
compress="xz"
7. 内核参数优化
7.1 systemd 相关内核参数
| 参数 | 说明 | 示例 |
|---|---|---|
systemd.unit= | 指定启动目标 | systemd.unit=multi-user.target |
systemd.log_level= | 日志级别 | systemd.log_level=debug |
systemd.confirm_spawn | 确认进程创建 | systemd.confirm_spawn=1 |
systemd.show_status | 显示启动状态 | systemd.show_status=1 |
systemd.default_timeout_start_sec | 默认超时 | systemd.default_timeout_start_sec=30 |
7.2 设置内核参数
# 临时设置(重启后失效)
sudo grubby --update-kernel=ALL --args="systemd.unit=multi-user.target"
# 永久设置
sudo grubby --update-kernel=ALL --args="systemd.default_timeout_start_sec=30"
# 查看当前参数
cat /proc/cmdline
7.3 跳过不必要的初始化
# 禁用 plymouth(启动画面)
sudo grubby --update-kernel=ALL --args="rd.plymouth=0 plymouth.enable=0"
# 禁用 SELinux(测试环境)
sudo grubby --update-kernel=ALL --args="enforcing=0"
8. 禁用不需要的服务
8.1 分析启用的服务
# 列出所有启用的服务
systemctl list-unit-files --state=enabled
# 查看哪些服务会拖慢启动
systemd-analyze blame | head -20
8.2 常见可禁用的服务
| 服务 | 说明 | 适用场景 |
|---|---|---|
NetworkManager-wait-online.service | 等待网络就绪 | 服务器/容器 |
cups.service | 打印服务 | 无打印机的服务器 |
ModemManager.service | 调制解调器管理 | 无调制解调器 |
accounts-daemon.service | 用户账户服务 | 服务器 |
avahi-daemon.service | mDNS/DNS-SD | 不需要 mDNS 的环境 |
firewalld.service | 防火墙 | 使用 iptables 的服务器 |
postfix.service | 邮件服务 | 不需要本地邮件 |
8.3 批量禁用
# 禁用单个服务
sudo systemctl disable cups.service
sudo systemctl mask cups.service # 彻底禁止
# 批量禁用(服务器环境)
for service in cups avahi-daemon accounts-daemon ModemManager; do
sudo systemctl disable ${service}.service
sudo systemctl mask ${service}.service
done
⚠️ 注意:mask 比 disable 更强,被 mask 的服务无法被手动或依赖启动。谨慎使用。
9. 实际案例
9.1 服务器启动优化
优化前:启动耗时 45 秒
# 1. 分析启动时间
systemd-analyze
# Startup finished in 2.5s (firmware) + 3.2s (loader) + 1.8s (kernel) + 8.5s (initrd) + 28.9s (userspace) = 44.9s
# 2. 分析耗时服务
systemd-analyze blame | head -10
# 15.234s NetworkManager-wait-online.service
# 5.678s firewalld.service
# 3.456s cups.service
# 2.345s avahi-daemon.service
# ...
# 3. 优化
sudo systemctl disable NetworkManager-wait-online.service
sudo systemctl disable cups.service
sudo systemctl disable avahi-daemon.service
sudo systemctl mask cups.service
sudo systemctl mask avahi-daemon.service
# 4. 优化 initramfs
sudo dracut --force --hostonly
# 5. 优化超时
sudo grubby --update-kernel=ALL --args="systemd.default_timeout_start_sec=15"
优化后:启动耗时 18 秒
systemd-analyze
# Startup finished in 2.5s (firmware) + 3.2s (loader) + 1.8s (kernel) + 6.5s (initrd) + 4.2s (userspace) = 18.2s
9.2 容器快速启动
# /etc/systemd/system.conf.d/container.conf
[Manager]
DefaultTimeoutStartSec=10s
DefaultTimeoutStopSec=10s
DefaultDeviceTimeoutSec=5s
# 最小化 systemd 单元
sudo systemctl mask systemd-logind.service
sudo systemctl mask systemd-resolved.service
sudo systemctl mask systemd-networkd.service
# 使用 networkd 替代 NetworkManager
sudo systemctl enable systemd-networkd.service
10. 启动性能基准测试
10.1 自动化测试脚本
#!/bin/bash
# boot-benchmark.sh
RUNS=5
TOTAL=0
echo "Running boot benchmark ${RUNS} times..."
for i in $(seq 1 ${RUNS}); do
echo "Run ${i}/${RUNS}..."
sudo reboot
sleep 60 # 等待系统重启
BOOT_TIME=$(systemd-analyze | grep "startup" | grep -oP '[0-9]+\.[0-9]+s' | tail -1)
echo "Boot time: ${BOOT_TIME}"
TOTAL=$(echo "${TOTAL} + ${BOOT_TIME}" | bc)
done
AVERAGE=$(echo "${TOTAL} / ${RUNS}" | bc)
echo "Average boot time: ${AVERAGE}s"
10.2 持续监控
# 记录每次启动时间到日志
echo "$(date): $(systemd-analyze | grep 'startup')" >> /var/log/boot-times.log
# 生成报告
systemd-analyze blame > /var/log/boot-blame-$(date +%Y%m%d).log
systemd-analyze critical-chain > /var/log/boot-chain-$(date +%Y%m%d).log
⚠️ 注意事项
- 不要盲目禁用服务:某些服务禁用可能导致系统功能异常
- 测试环境先验证:优化措施应在测试环境验证后再应用到生产
- 备份配置:优化前备份
/etc/systemd/system.conf和 GRUB 配置 - 监控关键服务:优化后监控关键服务是否正常启动
- 固件时间:firmware 和 loader 阶段通常无法通过软件优化
💡 提示
systemd-analyze plot的 SVG 图是分析启动并行度的最佳可视化工具NetworkManager-wait-online.service是常见的启动瓶颈,服务器通常可以安全禁用- 使用
systemd-analyze verify检查 unit 文件的正确性 - 固态硬盘(SSD)对启动时间的提升最为显著
- 容器环境可以跳过大部分硬件检测,启动速度更快