0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux服务器的启动链路优化实战

马哥Linux运维 来源:马哥Linux运维 2026-05-27 11:37 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

背景与现象

服务器开机慢不是小问题。在物理机房,这意味着 IDC 运维人员需要等待更长时间才能将机器交付使用;在云环境,慢启动意味着 ECS 实例在故障迁移或弹性扩缩容后不能及时恢复业务;在容器时代,Pod 启动慢会直接影响 Kubernetes 调度效率,进而影响整个集群的资源利用率。

常见的慢启动表现:

服务器按下电源键后,需要等待 3~5 分钟才能进入登录界面

systemd-analyze time显示 boot 时间超过 2 分钟,但不确定时间花在了哪里

系统明明硬件不差(SSD、多核 CPU、大内存),启动却比旧机器还慢

云服务器重置后首次启动极慢,但之后再启动就正常了

业务容器由于依赖的基础镜像启动慢,导致整个 deployment 扩容耗时超过 10 分钟

应用进程启动后需要等待大量依赖服务就绪(数据库、消息队列),但这些服务的启动顺序没有经过优化

系统更新内核后,首次启动特别慢,但之后就正常了

服务器的启动链路是一段长长的时序依赖链:固件初始化 → bootloader 加载 → 内核引导 → initramfs 挂载根文件系统 → systemd 拉起系统服务 → 业务应用监听端口。任何一步的延迟都会累积,最终表现为"开机慢"。本文的目标是:建立一套系统化的启动链路分析方法,从按下电源到服务就绪,逐一拆解每个阶段的耗时,找到瓶颈所在,给出具体优化手段,并验证优化效果。

工具准备

工具 用途 默认包名
systemd-analyze time 显示启动各阶段耗时 systemd 内置
systemd-analyze blame 按耗时排序显示所有 systemd unit systemd 内置
systemd-analyze critical-chain 显示关键路径(最长的服务链) systemd 内置
journalctl 查看系统日志 systemd 内置
dmesg 查看内核日志 内置
systemd-bootchart 启动过程可视化 systemd-bootchart
dracut 管理 initramfs dracut
grubby 修改 GRUB 配置 dracut

第一阶段:测量——先搞清楚时间花在哪里

1.1 用 systemd-analyze 量化各阶段耗时

服务器启动大致分为这几个阶段:

固件(BIOS/UEFI)
→ bootloader(GRUB)
→ 内核引导(kernel)
→ initramfs
→ systemd(基础服务和用户服务)
→ 业务服务就绪

查看整体启动耗时:

systemd-analyze time

典型输出:

Startup finishedin1min 30.284s (firmware) + 5.123s (bootloader) +
2.234s (kernel) + 15.678s (initramfs) + 1min 12.456s (userspace)
= 3min 6.775s

graphical.target @1min 12.456s + 234ms

这个输出告诉我们:

固件阶段(firmware)花 了 1 分 30 秒——这通常是最容易被忽视的瓶颈。BIOS/UEFI 自检、RAID 卡初始化、硬件发现都在这个阶段

bootloader花了 5 秒——GRUB 菜单等待和内核加载时间

内核引导花了 2.2 秒——内核解压和早期初始化

initramfs花了 15.7 秒——这是常被忽略的阶段,涉及根文件系统挂载、LVM/RAID 解锁等

用户空间(userspace)花了 1 分 12 秒——systemd 拉起所有服务,是优化的主战场

1.2 找出拖慢 systemd 的服务

systemd-analyze blame | head -30

输出按耗时降序排列:

1min 2.345s NetworkManager-wait-online.service
  45.123s mysqld.service
  32.456s docker.service
  28.901s redis.service
  15.678s postfix.service
  12.345s tuned.service
  8.901s rsyslog.service
  5.432s abrtd.service
  3.210s cups.service

重点关注:

NetworkManager-wait-online.service或network-online.target:如果网络依赖服务多,这个服务会等待网络就绪,时间可能很长

数据库服务(mysqld、postgres、redis):通常在 userspace 阶段最靠后,但如果它们依赖的数据目录在网络存储(NFS)上,会因为 NFS 挂载慢而被拖住

docker.service:Docker 守护进程启动时会加载镜像层,如果磁盘 IO 慢,会严重影响启动时间

postfix.service:服务器不使用邮件发送可以关闭

abrtd.service/cups.service:自动 bug 报告和打印机服务,生产服务器不需要

1.3 追踪最长的服务依赖链

systemd-analyze critical-chain

这会显示从multi-user.target回溯到启动起点的最长路径:

multi-user.target @1min 12.456s
└─ mysqld.service @1min 10.234s + 2.222s
 └─ network.target @1min 8.000s
  └─ NetworkManager-wait-online.service (waiting) @1min 2.345s

这里可以清楚看到:

mysqld.service自身启动花了 2.222 秒

但更重要的是它被network.target和NetworkManager-wait-online.service阻塞了 1 分 2 秒

真正拖慢 MySQL 启动的,不是 MySQL 本身,而是网络就绪等待时间

1.4 查看内核日志中的时间戳

dmesg -T | head -100

-T参数让时间戳可读(从内核启动以来的秒数变成了实际时间)。关注这些行:

[Mon May 25 1000 2026] Linux version 5.4.0-generic ...
[Mon May 25 1000 2026] Command line: BOOT_IMAGE=/boot/vmlinuz-5.4.0-generic root=UUID=xxx ro quiet splash
[Mon May 25 1001 2026] ACPI: Core revision 20190816
[Mon May 25 1001 2026] CPU: Physical Processor ID: 0
[Mon May 25 1001 2026] Spectre V2 : Vulnerable: Minimal microcode patch
[Mon May 25 1003 2026] SCSI subsystem initialized
[Mon May 25 1004 2026] Block layer SCSI generic (bsg) driver
[Mon May 25 1005 2026] VFS: Mounted root (ext4 filesystem) on device 8:1
[Mon May 25 1008 2026] systemd[1]: Starting Journal Service...
[Mon May 25 1008 2026] systemd[1]: Started Journal Service.
[Mon May 25 1010 2026] systemd[1]: Started Network Time Service.
[Mon May 25 1045 2026] systemd[1]: Reached target Network is Online.

方括号里的时间如果前后跳跃很大(比如从 1005 到 1010 之间跳跃了 65 秒),说明那里有长时间的等待(通常是 RAID 卡初始化、LUKS 解锁或网络存储挂载)。

第二阶段:逐段优化

2.1 固件阶段(BIOS/UEFI)优化

固件阶段耗时长的常见原因:

做了完整的硬件自检(POST)

BIOS 中开启了不需要的外设(串口、并口、软驱)

启用了 PXE 网络引导但最终失败回退

启用了 Intel VT-d 或 AMD-V 虚拟化扩展,但硬件不支持(BIOS 层面回退)

阵列卡(RAID Card)做了电池充放电校准(Battery Backup Unit conditioning)

开启了安全启动(Secure Boot)但每次启动都要验证签名

阵列卡做了 Consistency Check(一致性检查),这个过程在每次启动时可能运行

优化手段:

进入 BIOS/UEFI,禁用不使用的硬件接口:软驱、串口、并口、PS/2 键盘鼠标(如果用 USB

如果使用 RAID 卡,进入 RAID BIOS 检查是否有 BBU 相关问题或正在进行的维护。如果阵列卡支持缓存(Cache)和 BBU,BBU 的健康状态会直接影响性能:

BBU 损坏或电量低时,RAID 卡会禁用写缓存(Write Cache),所有写操作直接落盘,巨慢

定期的 BBU 学习周期(Learn Cycle)也会导致临时性能下降

# Dell 服务器:查看硬件告警和 RAID 卡状态
sudo omreport chassis alerts
sudo omreport storage controller action=verify

# HPE 服务器:查看阵列卡状态
sudo hpacucli ctrl all show status
hpacucli ctrl all show config detail

# 查看 Dell iDRAC 日志(如果存在)
sudo ipmitool sel list

确认启动顺序正确,确保从目标磁盘启动,而不是先尝试 PXE 或其他可启动设备:

如果 BIOS 中有 "Boot Order" 或 "Hard Drive Sequence",把目标磁盘放到第一位

关闭 "Boot from LAN" 或 "PXE Boot" 选项

如果启动顺序混乱导致每次都要扫描所有设备,固件阶段就会很慢。进入 BIOS 设置 → Boot → 精确指定启动磁盘。

风险提醒:BIOS 设置错误可能导致无法启动或硬件不被识别。修改前在纸上或手机里记录原始值,以便回滚。

2.2 Bootloader(GRUB)阶段优化

GRUB 阶段耗时主要来自:

GRUB 菜单等待超时(默认 5 秒)

加载了多个内核映像

启用了 GRUB 密码保护但每次启动验证耗时

每次启动都要解密 GRUB 加密磁盘(如果 /boot 是加密的)

优化手段:

# 查看当前 GRUB 配置
grep -E"timeout|GRUB_TIMEOUT"/etc/default/grub

# 修改 GRUB 等待时间为 1 秒(保留 1 秒足够在需要时手动进入菜单)
sudo sed -i's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=1/'/etc/default/grub

# 如果确定不需要图形化启动菜单,可以设为 0(但注意:设为 0 后,
# 如果需要进入 GRUB 菜单,需要在启动时按住 Esc 或 Shift)
# 设为 0 适合:云服务器、自动化管理的物理机
# 保留 1 秒适合:需要手动干预的服务器
sudo sed -i's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=0/'/etc/default/grub

# 重新生成 GRUB 配置
sudo update-grub # Debian/Ubuntu
# 或
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/CentOS 7

# 验证 GRUB 配置已更新
grep timeout /boot/grub2/grub.cfg
grep -c"menuentry"/boot/grub2/grub.cfg # 看有多少个启动项

如果系统有多个内核版本,也可以清理旧内核,减少 GRUB 扫描时间:

# 查看当前使用的内核版本
uname -r

# 查看已安装的内核版本
rpm -q kernel

# 清理旧内核(保留当前内核和最新内核)
sudo yum install yum-utils -y
sudo package-cleanup --oldkernels --count=2 # 保留最近 2 个内核

# 或者在 Debian/Ubuntu 上
sudo apt-get autoremove --purge -y

2.3 内核引导阶段优化

内核引导阶段耗时长的原因:

initramfs 过大(包含了太多模块和启动脚本)

根文件系统(rootfs)所在的磁盘 IO 慢(特别是通过 USB 或 SATA 慢速盘启动)

开启了太多内核启动参数(如没加quiet导致输出大量日志,延迟了后续阶段)

根分区加密(LUKS)导致每次启动需要输入密码或解密

启用了过多非必要的内核模块(如 Nouveau 驱动、没用到的硬件驱动)

优化手段:

检查initramfs大小:

ls -lh /boot/initramfs-*.img

# 如果 initramfs 超过 100MB(对于标准服务器来说偏大),查看包含的模块
lsinitcpio /boot/initramfs-$(uname -r).img -l # Arch Linux
dracut --show-modules # RHEL/CentOS,列出所有可用模块

initramfs 体积大的原因通常是包含了太多硬件驱动模块,特别是:

多个 RAID 卡驱动(如果只用一个)

多个网络驱动(如果机器只有一个网卡)

包含了所有文件系统驱动(即使只用一个 ext4)

精简 initramfs:

# 在 /etc/dracut.conf.d/ 中添加排除规则
# /etc/dracut.conf.d/custom.conf
omit_dracutmodules+="network nfs"
# 重新生成精简后的 initramfs(不包含网络、NFS 等模块)
sudo dracut -f --omit"network nfs"/boot/initramfs-$(uname -r).img $(uname -r)

# 验证
ls -lh /boot/initramfs-$(uname -r).img

精简内核启动参数:

# 查看当前启动参数
cat /proc/cmdline

# 输出示例:
# BOOT_IMAGE=/boot/vmlinuz-5.4.0-generic root=UUID=xxx ro quiet splash rhgb

通常服务器不需要rhgb(Red Hat Graphical Boot,图形化启动进度条)和splash(启动画面):

# 编辑 /etc/default/grub
# 找到 GRUB_CMDLINE_LINUX_DEFAULT,将 quiet splash rhgb 改为 quiet
sudo sed -i's/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash rhgb"/GRUB_CMDLINE_LINUX_DEFAULT="quiet"/'/etc/default/grub
sudo update-grub

如果根分区使用 LUKS 加密,可以通过添加密钥文件实现自动解锁(注意:密钥文件保存在 /boot 或独立分区,适合有物理安全控制的机房):

# 创建密钥文件(仅 root 可读)
sudo ddif=/dev/urandom of=/root/luks-keyfile bs=512 count=4
sudo chmod 600 /root/luks-keyfile

# 将密钥文件添加到 LUKS 加密卷
sudo cryptsetup luksAddKey /dev/sda3 /root/luks-keyfile

# 编辑 /etc/crypttab,让系统使用密钥文件自动解锁
# 格式:   
# cipherserver: UUID=xxx /root/luks-keyfile luks,timeout=30

风险提醒:LUKS 自动解锁密钥文件保存在/root中,如果磁盘被物理拿走,密钥文件也随之暴露。只有在有物理安全控制的机房环境中才适合使用自动解锁。

2.4 initramfs 阶段优化

initramfs 阶段主要做两件事:加载必要的硬件驱动、挂载根文件系统。这个阶段常见的瓶颈:

软 RAID 5/6 的 metadata 读取慢

根文件系统是 LVM 或 Btrfs,导致挂载耗时

根分区在 USB 设备或网络存储上

判断是否是 initramfs 阶段慢:

如果dmesg中显示从[ 5.678]到[ 18.567](约 13 秒)之间没有太多日志输出,但紧接着是大量 SCSI 或块设备初始化日志,说明 initramfs 在等待某个设备就绪。

# 查看 initramfs 里的启动脚本(以 RHEL 为例)
ls /usr/lib/dracut/modules.d/
cat /usr/lib/dracut/modules.d/50udev/rules.pl | head -20

优化手段:

# 如果不需要 LVM(很多云服务器是单盘,不用 LVM),可以禁用
# 编辑 /etc/dracut.conf.d/skip_lvm.conf
omit_dracutmodules+="lvm dm"

# 重新生成 initramfs
sudo dracut -f --omit"lvm dm mdmon"/boot/initramfs-$(uname -r).img $(uname -r)

对于 Btrfs 根文件系统,启动时需要做文件系统检查(fsck),如果分区很大,这个过程可能很慢:

# 检查 / 分区的文件系统类型
df -Th /

# 如果是 btrfs,看是否开启了自动碎片整理(btrfs balance)
sudo btrfs balance status / -d

2.5 systemd 服务阶段优化

这是最值得深入优化的阶段。systemd-analyze blame的输出直接指出了哪些服务拖慢了启动。

优化一:消除不必要的服务等待

NetworkManager-wait-online.service:

这个服务会等待网络完全就绪(所有网络接口都 up 且有 IP)才认为完成。如果某个网卡配置了 DHCP 但 DHCP 服务器响应慢,整个启动就会被阻塞。

# 查看该服务的状态和配置
systemctl status NetworkManager-wait-online.service
systemctl cat NetworkManager-wait-online.service

这个服务的等待时间是有限制的,但默认值可能很长(300 秒)。检查当前超时设置:

# 查看 NetworkManager-wait-online 的超时配置
grep -r"Timeout"/etc/systemd/system/NetworkManager-wait-online.service.d/ 2>/dev/null

方案 A:检查网络为什么就绪慢

# 查看启动时网络接口状态
journalctl -b -u NetworkManager | grep -E"Interface|state|DHCP"

方案 B:缩短超时时间(如果业务不需要等待所有网络就绪)

# 方法:通过 systemd override 文件覆盖超时配置
sudo systemctl edit NetworkManager-wait-online.service
[Service]
TimeoutStartSec=10sec

方案 C:对于不需要network-online目标的服务,取消对它的依赖(改用network.target而不是network-online.target)

# 查看哪些服务依赖了 network-online
systemctl list-dependencies mysqld.service | grep -E"network|Network"

优化二:并行化无依赖的服务

systemd 默认会根据服务文件的After=和Before=声明自动并行化。但有时候服务之间的隐式依赖(没写在After=里但实际上需要先启动)会导致串行启动。

# 查看某个慢服务的依赖关系(排除隐式依赖)
systemctl list-dependencies redis.service
systemctl cat redis.service | grep -E"After|Wants|Requires|Before"

优化并行启动:

如果两个服务实际上没有资源冲突,可以减少After=里的等待目标:

# /etc/systemd/system/redis.service.d/override.conf
[Unit]
# 在 local-fs.target 就绪后即可启动,不一定要等 network-online
After=network.target local-fs.target
Wants=local-fs.target

如果服务使用了ConditionPathExists或AssertPathExists但路径检查很慢,可以优化检查条件。

优化三:延迟启动非关键服务

对于不必须在系统启动时就运行的服务(如日志采集、监控 agent、备份任务),可以让它们延迟启动,在系统完全就绪后再启动:

# /etc/systemd/system/monitoring-agent.service.d/override.conf
[Unit]
# 延迟 2 分钟启动,给关键服务先完成的时间
[Timer]
OnBootSec=2min
OnUnitActiveSec=1hour

对于更精细的控制,可以用systemd-run配合 cron:

# 在 /etc/cron.d/ 中添加延迟启动任务
@reboot sleep 5 && /usr/local/bin/monitoring-agent.sh

优化四:数据库服务优化

MySQL/MariaDB、PostgreSQL、Redis 等数据库启动慢的常见原因:

数据目录在网络存储(NFS)上:数据库启动时需要 fsync 操作,NFS 延迟高会导致启动极慢

InnoDB 缓冲池大:MySQL 8.0 在启动时会 pre-load 缓冲池(innodb_buffer_pool_load_at_startup,默认开启),如果缓冲池 32GB+,这个过程需要几十秒

Redo log 大:启动时要做 checkpoint 和恢复

PostgreSQL WAL 回放:如果 Write-Ahead Log 文件很多,恢复时间会很长

MySQL 启动优化:

# 查看 MySQL 启动日志中的 InnoDB 恢复时间
sudo journalctl -u mysqld --since"10 minutes ago"| grep -i"innodb"
# 或查看 MySQL error log
sudo tail -100 /var/log/mysql/error.log | grep -E"InnoDB|Starting|Buffer pool"
# /etc/my.cnf 或 /etc/mysql/my.cnf
[mysqld]
# 如果缓冲池很大(>64GB),可以分阶段加载
# 关闭启动时预加载(加快启动,但首次访问会慢)
innodb_buffer_pool_load_at_startup = OFF

# 启动后手动触发,不阻塞系统启动
# 在 /etc/rc.local 中添加:
# sleep 30 && mysql -e "SET GLOBAL innodb_buffer_pool_load_now=ON;"
# 查看 InnoDB 缓冲池加载状态
mysql -e"SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';"

PostgreSQL 启动优化:

# PostgreSQL 启动慢通常是 WAL 回放慢,检查 WAL 文件数量
ls -t /var/lib/postgresql/data/pg_wal/ | head -20
# 如果 WAL 文件很多,可能是复制槽(Replication Slot)积压或归档失败

# 检查 PostgreSQL 日志
sudo journalctl -u postgresql --since"10 minutes ago"
sudo tail -100 /var/log/postgresql/postgresql-*-main.log
# /etc/postgresql/*/postgresql.conf
# 减少 checkpoint 频率相关的参数(生产环境要权衡)
checkpoint_timeout = 15min  # 默认 5min,可以适当增大减少 checkpoint 刷盘
max_wal_size = 4GB      # 单次 checkpoint 最大 WAL 量

Redis 启动优化:

# Redis 启动慢的原因通常是:
# 1. AOF 持久化文件很大,启动时要做 rewrite
# 2. maxmemory 设置了但没有正确配置淘汰策略
# 3. 有很多过期 key 需要在启动时清理

# 查看 Redis 持久化配置
redis-cli config get save
redis-cli config get appendonly

Redis RDB 持久化配置优化:

# redis.conf
# 合理的 save 策略(不要过于频繁)
save 900 1   # 至少 900 秒有 1 次修改才保存
save 300 10  # 至少 300 秒有 10 次修改
save 60 10000 # 至少 60 秒有 10000 次修改
# 禁止在启动时自动 BGSAVE:
# 如果需要手动备份,用:redis-cli BGSAVE

如果 Redis AOF 文件很大(超过几 GB),启动时重写会很慢:

# 查看 AOF 文件大小
ls -lh /var/lib/redis/appendonly.aof

# 如果 AOF 文件过大,执行 bgrewriteaof
redis-cli bgrewriteaof

# 调整 AOF 重写策略
redis-cli configsetauto-aof-rewrite-min-size 256mb
redis-cli configsetauto-aof-rewrite-percentage 100

优化五:Docker 守护进程优化

Docker 启动慢通常是因为:

docker.service加载所有镜像层到内存(overlay2 存储驱动初始化)

devicemapper 或 overlay2 存储驱动的元数据初始化

容器运行时加载大镜像

Docker daemon 启动时要连接 container registry 检查镜像签名

# 查看 docker.service 的启动耗时
systemd-analyze blame | grep docker

# 查看 dockerd 的启动日志
journalctl -u docker -n 50

Docker 启动优化:

# /etc/docker/daemon.json
{
"storage-driver":"overlay2",
"log-driver":"json-file",
"log-opts": {
 "max-size":"100m",
 "max-file":"3"
 },
"live-restore":true,
"default-ulimits": {
 "nofile": {"Name":"nofile","Hard": 65536,"Soft": 65536}
 }
}

live-restore: true允许 Docker 守护进程重启时容器继续运行,减少业务中断。这是容器化应用最重要的容错设置之一。

对于大镜像场景,可以考虑:

镜像分层优化:减少镜像层数,合并相似 RUN 指令

使用多阶段构建(multi-stage build)减小最终镜像体积

定期清理不用的镜像:

# 清理未使用的镜像(谨慎操作)
docker image prune -a --filter"until=168h"# 删除 7 天前未被使用的镜像

优化六:关闭不必要的系统服务

常见可以安全关闭的服务(取决于具体场景):

# 查看所有活跃服务,按启动耗时排序
systemctl list-units --type=service --state=active | 
 awk'{print $1}'| xargs -I {} systemd-analyze time {} 2>/dev/null | 
 grep -v"=0s"| sort -k3 -rn | head -20

# postfix:服务器不使用邮件发送可以关闭
sudo systemctldisable--now postfix

# tuned:性能调节守护进程,有些场景可以禁用
sudo systemctldisable--now tuned

# abrtd / abrt:自动 bug 报告,在生产服务器上通常不需要
sudo systemctldisable--now abrtd abrt-ccpp

# cups:打印机服务,服务器不需要
sudo systemctldisable--now cups

# 通过 systemctl mask 彻底禁用(比 disable 更强,mask 会让 systemctl start 也无法启动)
sudo systemctl mask postfix
sudo systemctl mask cups

如何安全判断一个服务是否可以关闭:

查看服务描述:systemctl cat

查看服务依赖:systemctl list-dependencies

在测试环境关闭该服务,观察是否有异常

确认关闭后不影响业务再在生产环境操作

2.6 挂载远程文件系统(NFS/v4)优化

如果/var或业务数据目录通过 NFS 挂载,NFS 服务器响应慢会直接拖慢所有依赖这些目录的服务。

优化手段:

在/etc/fstab中使用_netdev选项,确保网络就绪后再尝试挂载:

# /etc/fstab
10.0.0.100:/data /data nfs4 defaults,_netdev,async,noatime 0 0

_netdev:告诉 systemd 这是需要网络的挂载点,不要在网络就绪前尝试挂载

async:异步挂载,不等待服务器确认就返回(但有数据丢失风险,只适合内网)

bg:如果挂载失败,放到后台重试,不阻塞启动

设置合理的挂载超时:

10.0.0.100:/data /data nfs4 defaults,_netdev,timeo=30,retrans=3,soft 0 0

timeo=30:NFS 请求超时 3 秒(单位 0.1 秒)

retrans=3:重试 3 次后放弃

soft:超时后返回错误而不是无限重试(避免挂起)

风险提醒:async选项能加快挂载速度,但服务器端故障时可能丢失数据。只在确信网络可靠的内网环境中使用。

第三阶段:用 bootchart 可视化启动过程

systemd-bootchart可以生成启动过程的时间轴图表,直观看到 CPU 和磁盘 IO 在各阶段的分布。

# 安装
sudo yum install systemd-bootchart -y # RHEL/CentOS
# 或
sudo apt install systemd-bootchart -y # Debian/Ubuntu

# 启用(在 GRUB 中添加启动参数)
# 编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中加入 initcall_print
# 或直接用 systemctl enable
sudo systemctlenablebootchart

启动一次服务器后,查看生成的图表:

ls -lht /var/lib/bootchart/

生成的 PNG 图片显示了从内核启动到多用户模式之间,CPU 使用率、磁盘 IO 和各进程的启动时间线。如果在图中看到某个进程在启动后长时间占用 CPU(柱状图很高),或者某个服务在很长时间后才开始启动(时间线上空白很多),就找到了瓶颈。

第四阶段:验证优化效果

每次调整后,都要测量启动时间变化,形成对比数据:

# 记录优化前的启动时间(重启前执行一次)
systemd-analyze time > /tmp/boot_before.txt
systemd-analyze blame | head -30 > /tmp/blame_before.txt

# 实施优化
# ...

# 重启并测量
systemd-analyze time > /tmp/boot_after.txt
systemd-analyze blame | head -30 > /tmp/blame_after.txt

# 对比
echo"=== 启动时间对比 ==="
diff /tmp/boot_before.txt /tmp/boot_after.txt

echo"=== 服务耗时对比(只显示变化)==="
diff /tmp/blame_before.txt /tmp/blame_after.txt

同时记录dmesg中的时间戳变化:

# 记录内核各阶段的时间戳
dmesg -T | grep -E"^[.*] (VFS|Linux|SCSI|systemd|Started)"| head -50 > /tmp/dmesg_after.txt

记录以下关键时间点:

内核解压和初始化完成

根文件系统挂载完成

systemd 第一个服务启动

网络就绪

最慢服务启动完成

SSH/业务端口就绪

第五阶段:建立常态化监控

启动时间也应该纳入监控。一个简单的方法是让 systemd 在启动后将耗时写入一个文件,由监控 agent 采集:

# /etc/systemd/system/boot-metric.service
[Unit]
Description=Export boot time metric to Prometheus textfile collector
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/bin/bash -c'
 FIRM=$(systemd-analyze time 2>/dev/null | grep firmware | awk "{print $2}" | sed "s/s//"); 
 KERN=$(systemd-analyze time 2>/dev/null | grep "kernel" | awk "{print $2}" | sed "s/s//"); 
 USER=$(systemd-analyze time 2>/dev/null | grep userspace | awk "{print $2}" | sed "s/s//"); 
 echo "linux_boot_firmware_seconds ${FIRM:-0}" > /run/touch boot-metric.prom; 
 echo "linux_boot_kernel_seconds ${KERN:-0}" >> /run/touch boot-metric.prom; 
 echo "linux_boot_userspace_seconds ${USER:-0}" >> /run/touch boot-metric.prom'

[Install]
WantedBy=multi-user.target
# 启用并立即执行
sudo systemctlenableboot-metric.service
sudo systemctl start boot-metric.service
cat /run/touch boot-metric.prom

Prometheus node_exporter 的--collector.textfile.directory指向/run/touch(RHEL)或/var/lib/node_exporter/textfile_collector(Debian),即可将启动时间纳入监控曲线。在 Grafana 中设置告警:当linux_boot_userspace_seconds > 120时触发告警。

云环境和虚拟化场景的特殊考量

公有云 ECS 实例启动优化

在云环境中,服务器的启动链路与物理机有所不同。云厂商在底层做了大量虚拟化工作,有些阶段会被云平台接管,有些则会因为虚拟化而变慢。

公有云常见的慢启动原因:

云盘快照恢复慢:从云盘快照创建的 ECS 实例,启动时需要从对象存储恢复数据,这个过程比本地 SSD 盘慢得多

虚拟化初始化:云平台的 hypervisor 需要为 VM 分配 vCPU、vRAM、虚拟网卡等资源,这个阶段由云平台控制,优化空间有限

云监控 agent 启动:云厂商的监控 agent(阿里云 cloudmonitor、腾讯云管家、AWS SSM Agent)在 VM 启动时需要注册到云平台,可能会有网络等待

优化手段:

# 在云控制台创建 ECS 时:
# 1. 选择本地 SSD 盘(ephemeral,盘)而不是云盘(标准云盘 / SSD 云盘)
#  本地 SSD 延迟低(微秒级),但数据不持久化,适合临时环境

# 2. 如果必须用云盘,选择 ESSD(超高速云盘)而不是普通 SSD 云盘
#  ESSD 的 IOPS 和吞吐远高于普通云盘

# 3. 在云控制台中预先设置自定义镜像(包含所有依赖)
#  用预装了应用的镜像创建实例,而不是启动后再安装软件

# 检查云实例启动过程的各个阶段耗时
# 阿里云:在控制台查看实例启动历史
# AWS CloudWatch:查看 EC2 "instance-state" 日志

Kubernetes 节点启动优化

在容器编排环境中,节点(Node)本身也是一台 Linux 服务器。节点的启动时间直接影响 Pod 的调度和业务恢复速度。

K8s 节点启动慢的典型原因:

** kubelet 拉取基础镜像慢**:如果 Pod 调度到新节点,kubelet 需要拉取 pause 镜像和业务镜像,网络带宽不足时会拖慢启动

** kube-proxy 和 CNI 插件初始化**:网络插件(如 Calico、Cilium)启动时会做网络策略初始化

** volume 挂载慢**:挂载PersistentVolume(特别是远程 NFS 或云存储)需要等待存储就绪

节点污点(Taints)和容忍度( Tolerations):如果节点有特殊污点,Pod 需要等待匹配的容忍度才能调度

排查和优化:

# 查看节点状态和启动时间
kubectl get nodes -o wide
kubectl describe node  | grep -E"Kubelet Started| Conditions| System Info"

# 查看 kubelet 日志(看节点注册到集群的耗时)
journalctl -u kubelet -n 50 | grep -E"Starting|Registered|Ready"

# 查看 Pod 调度到节点后的启动时间
kubectl get pods -o wide --sort-by=.status.startTime | head -20

# 查看 Pod 启动过程中各阶段耗时(Kubernetes 1.27+)
kubectl alpha event | grep 

# 如果 Pod 卡在 ImagePullBackOff 或 ContainerCreating
kubectl describe pod  | grep -E"Events:|Warning"

# 常见问题:ImagePullBackOff(镜像拉取失败)
# 可能原因:镜像 tag 不存在、私有仓库认证失败、网络不通
# 解决:检查镜像地址、secrets、网络策略
# 优化 Pod 启动:设置合理的镜像拉取策略(imagePullPolicy)
# 不设置为 Always,减少重复拉取
spec:
containers:
-name:myapp
 image:myregistry.com/myapp:v1.2
 imagePullPolicy:IfNotPresent# 或 Always 或 Never

虚拟化平台(VMware/Hyper-V/KVM)启动优化

在虚拟化平台上,VM 的启动链路比物理机多了几个阶段:

虚拟机启动 → Hypervisor 分配资源 → Guest OS 启动 → ...

常见的虚拟化特有瓶颈:

存储延迟高:VM 的虚拟磁盘实际上是网络存储(iSCSI/NFS/云盘),IO 延迟远高于本地盘

内存过量分配(Memory Overcommit):ESXi 主机内存被过量分配,VM 启动时可能需要等待内存腾出

Hyper-V 检查点(Checkpoint)恢复:如果 VM 有检查点,恢复时会从检查点重建状态,非常慢

QEMU/KVM 模拟硬件初始化:模拟 SATA 控制器、虚拟网卡等比真实硬件慢

优化手段:

# VMware 环境:检查 VM 的硬件版本(越新越好)
# 使用 vSphere Client 查看 VM 硬件版本,升级到最新版本
# 硬件版本 17(ESXi 7.0)是目前较新的版本

# 禁用不必要的虚拟硬件(软盘、串口、并口)
# 在 vSphere Client 中编辑 VM 设置,移除不需要的设备

# 使用 PVSCSI(Paravirtual SCSI)控制器代替 LSI Logic
# PVSCSI 的 IO 性能远高于 LSI Logic,特别是高 IOPS 场景

# 如果使用 RDM(Raw Device Mapping),确保是物理模式而不是虚拟模式

故障复盘模板

【故障复盘】服务器启动慢

服务器型号 / 云实例规格:
操作系统版本:
内核版本:
发现时间:

启动耗时:
- 固件阶段:
- bootloader 阶段:
- 内核阶段:
- initramfs 阶段:
- systemd 阶段:
- 最慢服务(名称 + 耗时):

排查过程:
1. systemd-analyze time 发现总启动时间 [X分钟],其中 [阶段名] 最慢
2. systemd-analyze blame 发现 [服务A] 耗时 [Xs],原因是 [具体原因]
3. journalctl -u [服务A] 发现 [具体日志错误/阻塞原因]
4. ...

优化措施:
1. [操作内容:修改了哪个文件/配置] → 预期效果:[xxx]
2. ...

验证结果:
优化后总启动时间:从 [X分钟Y秒] 降到 [X分钟Y秒]
其中 [阶段名] 优化了 [Xs]

预防措施:
1. 常态化监控启动时间,告警阈值 [X秒]
2. 上线前在测试环境验证启动时间
3. ...

服务依赖链调试:如何找出隐式依赖

systemd 的服务依赖有两种:显式依赖(After=、Requires=)和隐式依赖(systemd 自动推断)。隐式依赖是排查串行启动的关键。

# 查看某个服务的完整依赖树(包括显式和隐式)
systemd-analyze dot redis.service | dot -Tpng > redis_deps.png

# 查看某个服务被哪些其他服务依赖
systemctl list-dependencies --reverse redis.service

# 查看哪些服务在等待 redis.service
systemctl list-dependencies redis.service --after
systemctl list-dependencies redis.service --before

# 查看服务文件中的所有依赖声明
systemctl cat redis.service

# 如果发现服务 A 应该在服务 B 之前启动,但没有写进 After=,
# 可以用 override 文件添加依赖(不用改原始 service 文件)
sudo systemctl edit redis.service
# [Unit]
# After=network.target db.service
# 注意:如果 db.service 不存在,这个依赖声明不会生效

常见的隐式依赖导致串行启动的例子:

服务 A 写日志到/var/log/myapp.log,而/var是独立挂载的分区

服务 B 使用套接字文件/run/myapp.sock,而 systemd 在网络就绪后才创建/run

# 查看 /var 和 /run 的挂载情况(是否独立分区)
mount | grep -E"^/dev|/var |/run "

# 如果 /var 是独立挂载,服务启动时会等待 /var 先挂载
# 如果 /var 挂载到 NFS,NFS 挂载慢就会拖慢所有写 /var/log 的服务

systemd 服务启动顺序错误的调试方法

有时候服务应该并行启动但实际是串行启动,这是因为 systemd 的After=依赖关系没有正确配置。

# 查看两个服务的启动时间差
systemd-analyze plot > /tmp/boot.svg
# 生成 SVG 格式的启动时间图,可以用浏览器打开查看

# 查看服务 C 启动时,服务 D 的状态
systemctl show db.service -p ActiveState,SubState,ExecMainStatus

# 如果服务启动失败,查看失败原因
systemctl status failed
journalctl -u failed-service-name -xn

总结

服务器启动链路分析的核心路径:

systemd-analyze time(分段耗时,量化每个阶段)
→ systemd-analyze blame(排序找最慢服务)
→ journalctl -u [服务名](查服务启动日志,找阻塞原因)
→ dmesg -T(内核阶段时间戳,找早期瓶颈)
→ 针对性优化 → 重启验证 → 对比数据 → 常态化监控

常见启动瓶颈的快速对照表:

阶段 常见原因 优先处理
固件 RAID 卡校准、硬件自检、USB 枚举 检查阵列卡状态、禁用不必要外设
GRUB 菜单等待超时 减少 timeout 到 0~2 秒
内核 initramfs 过大、内核参数过多 精简 initramfs、清理内核启动参数
initramfs LVM/RAID 解锁慢、网络存储挂载 检查 RAID 卡、解锁流程、优化挂载选项
systemd network-wait-online、数据库、NFS、容器运行时 并行化、延迟启动、网络优化
业务服务 依赖未就绪、自身初始化慢 检查依赖链、分阶段启动

优化启动时间的核心思路是先测量再优化,不要凭感觉操作。systemd-analyze blame几乎能直接给出答案,大多数情况下真正的慢启动根因只有一个服务,找到它就解决了一大半。优化后一定要重新测量并记录,形成对比数据,才能知道优化是否真正有效。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 电源
    +关注

    关注

    185

    文章

    19060

    浏览量

    265172
  • Linux
    +关注

    关注

    88

    文章

    11863

    浏览量

    219880
  • 服务器
    +关注

    关注

    14

    文章

    10456

    浏览量

    91865

原文标题:为什么你的 Linux 服务器开机这么慢?启动链路优化实战

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    linux服务器和windows服务器

    Linux服务器和Windows服务器是目前应用最广泛的两种服务器操作系统。两者各有优劣,也适用于不同的应用场景。本文将 对Linux
    发表于 02-22 15:46

    教你linux搭建web服务器

    教你linux搭建web服务器和大家分享了一份配置文档,希望对您用linux搭建web服务器有所启发。
    发表于 12-28 14:18 9383次阅读

    基于Linux系统的FTP服务器的实现

    为了在Linux系统下实现安全、高效的FTP服务器,选择了具有小巧轻快、安全易用等优点的服务器软件vsftpd。通过对Linux平台下FTP网络服务
    发表于 07-24 15:36 39次下载

    Linux服务器排障相关的性能问题、优化和便利工具

    Linux排障技巧在数据中心十分受人重视。数据中心专家对此提供了一些Linux服务器排障相关的性能问题、优化和便利工具参考。
    的头像 发表于 09-03 10:29 2526次阅读

    服务器优化是什么,它的好处有哪些

    服务器优化提供一种提高服务器性能和速度的方法,因为企业需要采用服务器优化技术来满足其网站的可访问性、可用性和功能等期望。 一、什么是
    的头像 发表于 12-03 17:02 4868次阅读

    如何使用Checkmk监控Linux服务器

    `Checkmk` 是用于监控 Linux 服务器的最常用和用户友好的应用程序之一。它可以检查与您的 Linux 服务器连接的服务器状态、负
    的头像 发表于 02-17 10:46 2735次阅读
    如何使用Checkmk监控<b class='flag-5'>Linux</b><b class='flag-5'>服务器</b>?

    如何重新启动Linux服务器

    使用个人电脑工作的时候,可能会因为各种原因而关闭机器。对于 Linux 初学者来说,与电源相关(关机、重启等)的任务总是最后才想到如何去实现的,所以有可能对于如何重新启动远程服务器不太了解。今天我们介绍一些可以用来通过终端来重新
    的头像 发表于 05-14 16:03 3327次阅读

    Linux服务器性能查看方法

    Linux服务器性能查看是系统管理员和开发人员在日常工作中经常需要进行的任务,以确保系统稳定运行并优化资源使用。以下将详细介绍多种Linux服务器
    的头像 发表于 09-02 11:15 2894次阅读

    如何优化Linux服务器的性能

    优化Linux服务器的性能是一个综合性的任务,涉及硬件、软件、配置、监控等多个方面。以下是一个详细的指南,旨在帮助系统管理员和运维人员提升Linux
    的头像 发表于 09-29 16:50 1592次阅读

    服务器数据恢复—Linux网站服务器硬盘出现坏扇区的数据恢复案例

    服务器数据恢复环境: 一台linux操作系统网站服务器,该服务器上部署了几十个网站,使用一块SATA硬盘。 服务器故障&原因:
    的头像 发表于 10-09 16:26 1004次阅读

    服务器数据恢复—异常断电导致linux系统无法启动的数据恢复案例

    服务器数据恢复环境: 某品牌服务器+同品牌存储,Linux centos7+EXT4文件系统。 服务器故障: 意外断电导致服务器
    的头像 发表于 10-25 17:42 1693次阅读

    如何构建Linux服务器安全防护体系

    前言:作为一名运维工程师,我见过太多因为安全配置不当而被攻破的服务器。本文将分享我多年来积累的实战经验,教你如何构建一套完整的Linux服务器安全防护体系。
    的头像 发表于 08-05 17:35 1312次阅读

    华纳云服务器Linux系统电源管理与节能优化配置方法

    在云计算时代,Linux系统的电源管理优化成为提升云服务器能效的关键环节。本文将深入解析Linux内核的电源管理机制,从CPU调频策略到磁盘休眠设置,提供一套完整的节能配置方案。通过调
    的头像 发表于 08-21 15:09 1185次阅读

    Linux服务器性能调优的核心技巧和实战经验

    如果你正在为这些问题头疼,那么这篇文章就是为你准备的!作为一名拥有10年经验的运维工程师,我将毫无保留地分享Linux服务器性能调优的核心技巧和实战经验。
    的头像 发表于 08-27 14:36 1297次阅读

    服务器数据恢复—意外断电!Linux服务器数据恢复大揭秘

    某品牌服务器+存储,安装的linux操作系统。 机房意外断电导致服务器操作系统无法正常启动服务器管理员故障
    的头像 发表于 11-18 11:20 816次阅读