服务器重启一次要等好几分钟,这在追求快速恢复的生产环境里是件让人难受的事。更麻烦的是,开机慢往往不是那种"系统挂了"的显性故障,业务还能跑,只是恢复时间长、重启风险大,容易被人忽视。等到某天需要紧急重启时,才发现要等半天。
Linux 的启动过程大体是:固件(BIOS/UEFI)→ 引导加载程序(GRUB)→ 内核 → initramfs → systemd(用户空间)→ 各服务依次启动。现代发行版基本都由 systemd 接管服务启动,它提供了相当好用的分析工具,能精确告诉你"启动一共花了多少秒,每个环节、每个服务各花了多少"。这篇文章会带你用 systemd-analyze 系列命令定位慢在哪,重点排查最拖后腿的服务(常见的是网络等待、磁盘检查、DNS 超时、云初始化等),并给出具体的处置办法。
读完你应该能做到:重启后几分钟内定位到慢启动的根因,针对性地优化掉那些无谓的等待,把开机时间从几分钟压到几十秒甚至更短。文中给出的耗时数字都是常见量级参考,具体因机器和负载而异。
一、先量化:启动到底慢在哪
不要凭感觉说"开机慢",先用工具把时间拆开。
# 总览:固件、loader、内核、用户空间各阶段耗时
systemd-analyze
# 例:
# Startup finished in 3.1s (firmware) + 2.0s (loader) + 4.5s (kernel) + 1min 12.3s (userspace) = 1min 21.9s
# 按耗时排出启动中最慢的单元(服务)
systemd-analyze blame | head -30
# 看关键链(critical chain):哪条依赖链决定了总时长
systemd-analyze critical-chain
systemd-analyze critical-chain nginx.service # 看某服务在链上的位置
# 生成交互式/图形化的启动时序图(需要能看 SVG 的环境,可导出后看)
systemd-analyze plot > /tmp/boot.svg
# 查看每次启动的摘要
systemd-analyze time
journalctl --list-boots # 列出历史启动记录及编号
怎么读这些输出:
systemd-analyze的四个数字里,如果userspace很大(几十秒到几分钟),说明慢在服务启动,重点排查服务;如果kernel很大,可能是硬件探测、驱动、initramfs 问题;firmware大通常是 BIOS/UEFI 设置或自检慢。systemd-analyze blame按单个服务耗时排序,但要注意:耗时长的服务不一定在关键路径上。一个服务跑得久,如果它和别的服务并行、不阻塞后续,就不影响总时长。critical-chain才是判断"谁真正拖慢总时间"的关键。它展示的是一条串行依赖链,链上任何一环变慢,总启动时间就变长。
这是排查的核心思路:先看 systemd-analyze 定位阶段,再用 critical-chain 找到关键路径上的慢环节,最后用 blame 和日志确认具体原因。
二、常见的慢启动原因
根据经验,生产服务器开机慢主要集中在下面几类,可以对照 critical-chain 逐项排查。
| 慢启动原因 | 典型表现 | 耗时量级(经验值) |
|---|---|---|
| 网络等待(DHCP/网卡链路) | NetworkManager-wait-online 慢 |
数秒到 30+ 秒 |
| 磁盘 fsck 检查 | systemd-fsck / 大容量盘检查 |
数秒到数分钟 |
| 云初始化 | cloud-init 相关单元 |
5~60 秒 |
| DNS 解析超时 | 服务启动时反查主机名卡住 | 每次 5~30 秒 |
| 依赖网络的服务 | 服务配了 After=network.target 却等超时 |
数秒到数十秒 |
| 挂载失败重试 | 网络文件系统/NFS 不可达 | 数十秒 |
| 硬件/驱动探测 | 内核阶段慢,报 device timeout | 数秒到数十秒 |
| 大量小服务串行 | 依赖顺序不合理 | 累积数十秒 |
| 时钟/随机数 | systemd-random-seed 等 |
一般较小 |
下面逐个讲怎么确认和处理。
三、头号嫌疑:网络等待
NetworkManager-wait-online.service 是服务器上最常见的"背锅侠"。它的作用是"等网络真正可用",默认会等到网络就绪或超时。在网线没插、DHCP 慢、或网卡多而只配了一个的场景下,它能白白让开机多等几十秒。
# 确认它是不是慢
systemd-analyze blame | grep -i network
systemd-analyze critical-chain NetworkManager-wait-online.service
# 看它的实际状态
systemctl status NetworkManager-wait-online.service
systemctl is-enabled NetworkManager-wait-online.service
如果确认它拖慢了启动,而你的服务并不需要在网卡链路完全就绪前等待,可以考虑禁用它(风险提示:某些依赖网络已就绪的服务可能因此提前启动,需要确认业务顺序):
# 查看它被谁依赖
systemctl list-dependencies --reverse NetworkManager-wait-online.service
# 禁用(谨慎,确认业务不依赖它)
sudo systemctl disable NetworkManager-wait-online.service
# 回滚:重新启用
# sudo systemctl enable NetworkManager-wait-online.service
更稳妥的做法是保留它但缩短超时,或改用 network-online.target 的正确配置,而不是简单粗暴地禁掉。如果确实有服务必须等网络,应该给那个服务加 After=network-online.target 和 Wants=network-online.target。
另外,DHCP 慢也会拖时间。给服务器配静态 IP(见前面静态 IP 那篇)能显著减少这一阶段的等待。
四、磁盘 fsck 与挂载
文件系统检查(fsck)在大盘或非正常关机后可能耗时很久,尤其是 ext4 在大容量盘上。
# 看 fsck 相关单元耗时
systemd-analyze blame | grep -iE 'fsck|mount|dev-disk'
# 看某分区是否被设置为开机检查
sudo tune2fs -l /dev/vda1 | grep -iE 'check|mount count|max'
# ext4:调整最大挂载次数和检查间隔(谨慎,注意是设 0 表示不按计数检查)
sudo tune2fs -c 0 -i 0 /dev/vda1 # 关闭按次数/时间的自动检查(生产盘常用)
风险提示:
tune2fs -c 0 -i 0会让文件系统不再按挂载次数和时间自动 fsck,可靠性依赖业务自身的定期检查安排。执行前确认盘的文件系统类型(lsblk -f),对 XFS 该命令不适用(XFS 用xfs_admin等)。改错分区可能影响数据,务必核对设备名。
挂载失败重试也很常见,尤其 fstab 里有网络存储(NFS/CIFS)时。如果网络存储不可达,systemd 会按 x-systemd.device-timeout 和默认超时重试,造成长时间等待。
# fstab 里给网络挂载加超时和 nofail,避免拖慢启动
# 示例(noauto 表示不自动挂载,nofail 表示失败不阻塞启动)
# server:/data /mnt/data nfs _netdev,nofail,x-systemd.device-timeout=10 0 0
nofail 很关键:没有它,挂载失败会让系统进入紧急模式或长时间等待。对非关键的网络挂载,加上 nofail 是常见做法。
五、cloud-init 与云主机
云主机上,cloud-init 负责首次启动时注入配置。它在每次启动时也会跑,某些阶段(尤其是网络元数据获取)可能很慢。
# 看 cloud-init 各阶段耗时
systemd-analyze blame | grep -i cloud
cloud-init analyze show
cloud-init analyze blame
# 看 cloud-init 日志
cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log
journalctl -u cloud-init --no-pager | tail -50
如果云主机不需要每次启动都跑 cloud-init 的网络阶段,可以按云厂商的文档调整(比如配置 datasource_list 或禁用某些模块),但要注意别影响首次初始化能力。对新克隆/快照出来的机器,有时会因为残留的实例 ID 导致 cloud-init 卡住重试,表现为启动很慢——这种要在控制台确认或重建实例元数据。
DNS 反查与主机名解析超时
这是很隐蔽但非常常见的一类慢启动:服务或脚本启动时对某个主机名做正向或反向解析,DNS 服务器不可达,导致每次查询等待 5 秒以上的超时。
# 检查 /etc/hosts 和 /etc/resolv.conf
cat /etc/hosts
cat /etc/resolv.conf
# 测试反查是否慢
time getent hosts $(hostname)
time dig -x $(hostname -i 2>/dev/null)
time nslookup $(hostname)
# 看 resolv.conf 里的超时和重试设置
cat /etc/resolv.conf
# options timeout:2 attempts:2 之类
解决办法:把主机名解析写进 /etc/hosts(尤其是本机主机名),或者修正 DNS 配置、调小超时。很多"服务启动莫名的慢 5 秒、10 秒"都是这个原因。
# 在本机 hosts 里给主机名一个静态解析,避免启动时反查卡住
echo "127.0.0.1 $(hostname)" | sudo tee -a /etc/hosts
六、深入单个服务:看日志找原因
定位到某个慢服务后,用日志确认它到底在等什么。
# 以某次启动(-b)为范围看某服务的日志,加时间戳
sudo journalctl -b -u <服务名> --no-pager
sudo journalctl -b -u <服务名> -o short-precise --no-pager
# 看本次启动所有服务的日志里有无 timeout/fail
sudo journalctl -b --no-pager | grep -iE 'timeout|failed|timed out|retry'
# 看内核启动日志
sudo journalctl -k -b --no-pager
dmesg -T | less
# 看某服务的详细信息和超时配置
systemctl show <服务名> | grep -iE 'Timeout|After|Requires|Wants'
# 看服务本身和它的依赖
systemctl list-dependencies <服务名>
常见处置手段:
- 给服务调超时:在 drop-in 里设
TimeoutStartSec=,避免它长时间干等。 - 调整依赖顺序:用
After=/Before=明确顺序,用Wants=而非Requires=减少强依赖阻塞(要理解业务语义)。 - 延后非关键服务:把不紧急的服务改为
WantedBy=multi-user.target之外的目标,或用Type=idle让它更晚启动。 - 并行化:systemd 默认并行,别用
After=把本可并行的服务串起来。
# 安全的修改方式:drop-in 覆盖,不改原单元文件
sudo systemctl edit <服务名>
# 在打开的编辑器里写:
# [Service]
# TimeoutStartSec=30
内核与固件阶段的慢
如果 systemd-analyze 显示 firmware 或 kernel 阶段就慢,问题不在服务。
# 内核启动日志里找 device timeout、link down 等
sudo journalctl -k -b --no-pager | grep -iE 'timeout|reset|link|scsi|ata|nvme' | head -40
dmesg -T | grep -iE 'waiting|timeout|delay' | head
# 看 initramfs 大小和内容(过大也会影响)
ls -lh /boot/initramfs-*.img /boot/initrd.img-* 2>/dev/null
可能的处理:更新/更换驱动、检查 BIOS/UEFI 里是否开启了不必要的自检(memory test、网络启动 PXE 排在前面等)、减少 initramfs 里多余的模块。
七、优化前后的验证
每次改动都要能对比。
# 记录当前启动耗时基线
systemd-analyze > /tmp/boot-before.txt
systemd-analyze blame > /tmp/blame-before.txt
# 做改动后重启,再量一次
sudo reboot
# 重启后再看
systemd-analyze
systemd-analyze blame | head -20
systemd-analyze critical-chain
# 对比历史多次启动
journalctl --list-boots
sudo journalctl -b -1 -o short-precise | grep 'Startup finished'
一个务实的提醒:不是所有慢都值得优化。如果服务器一年只重启一次,把开机从 90 秒优化到 40 秒意义不大;但如果是需要频繁重启、或弹性伸缩的场景,每一秒都值钱。优化的目标是消掉"无谓的等待"(等网络、等 DNS 超时、等挂载重试),而不是追求理论最短。
常见问题
Q1:systemd-analyze blame 里某服务耗时最长,就是它的问题吗?
不一定。要看它是否在关键路径上。用 systemd-analyze critical-chain 判断,只有在关键链上的慢服务才真正影响总时长。
Q2:禁用 NetworkManager-wait-online 安全吗?
如果你的服务不依赖"网络完全就绪",通常可以禁用,能省不少时间。但若有关键服务必须等网络,禁用后可能启动失败,建议保留并给需要的服务单独配 After=network-online.target。
Q3:开机卡在某个服务很久,怎么知道它在等什么?
journalctl -b -u <服务名> 看该服务的日志,找 timeout、retry、DNS 查询等线索;必要时用 strace 跟踪进程系统调用(临时用,别在生产长期挂)。
Q4:为什么重启后第一次特别慢,之后正常?
常见于 fsck(非正常关机后触发)、cloud-init 首次初始化、页面缓存为空导致的服务冷启动。持续异常才对。
Q5:云主机开机总比物理机慢,正常吗?
云主机的固件阶段、元数据服务(如 cloud-init)会额外耗时,通常慢一些属正常。若明显异常,优先查 cloud-init 和网络等待。
总结
- 先量化再优化:
systemd-analyze看阶段耗时,critical-chain找关键路径,blame列单服务耗时,三者结合定位。 - 服务器慢启动最常见的原因是网络等待(
NetworkManager-wait-online)、fsck、cloud-init、DNS 反查超时和挂载重试,按此顺序排查效率最高。 - 网络类慢启动可通过配静态 IP、保留或调整
network-online.target依赖、给需要网络的服务单独声明依赖来改善。 - DNS 反查超时很隐蔽,把本机和关键主机名写入
/etc/hosts、修正 DNS 配置能显著减少无谓等待。 - 用 systemd drop-in(
systemctl edit)安全地调整服务超时和依赖,改前记录基线、改后重启实测对比;对不常重启的机器不必过度优化。
企业QQ咨询




