系统启动流程:从按下电源键到用户界面

大家好,我是老张。今天我们来聊聊系统启动流程。说实话,这可能是整个运维生涯里最基础也最关键的知识点。你想想看,服务器起不来,你连门都进不去,还谈什么后续排查?

我个人习惯把启动流程分成四个阶段:BIOS/UEFI、Bootloader、内核加载、init进程启动。每个阶段都有它独特的日志特征和排查技巧。咱们一个一个来看。

第一阶段:BIOS/UEFI 阶段

按下电源键的那一刻,CPU 首先执行的是固化在主板 ROM 里的代码。这就是 BIOS 或 UEFI。说白了,它负责最底层的硬件自检和初始化。

BIOS(Basic Input/Output System) 是老传统了,16位实模式,界面蓝底白字。而 UEFI(Unified Extensible Firmware Interface) 是后来者,32位或64位,支持图形界面,启动更快。

我在项目中遇到过一台老服务器,每次开机都要等 3 分钟才过 BIOS。后来发现是内存自检卡住了。嗯,这里要注意:BIOS 阶段的日志通常不写入操作系统,你得看屏幕输出或者主板上的 Debug 灯。

关键日志位置:

  • 屏幕输出:POST 卡(Power-On Self-Test)信息
  • 主板蜂鸣器:不同长短音代表不同错误
  • IPMI/BMC 日志:远程管理卡可以记录硬件事件

常见的排查点:

  • 内存条接触不良?重新插拔试试
  • 硬盘没识别?检查 SATA/SAS 线缆
  • 启动顺序错了?进 BIOS 调整 Boot Order

我的小技巧: 遇到 BIOS 阶段卡住,先看键盘灯。如果 Num Lock 灯能切换,说明 CPU 和基本电路没问题。如果灯都不亮,那大概率是主板或电源挂了。

第二阶段:Bootloader 阶段

BIOS/UEFI 自检通过后,会按照启动顺序去读取磁盘的第一个扇区(MBR)或者 EFI 系统分区。这里的主角就是 Bootloader。

Linux 下最常见的 Bootloader 是 GRUB2(Grand Unified Bootloader version 2)。它负责加载内核到内存,并传递启动参数。

我曾经遇到过一个经典问题:系统更新后重启,直接黑屏。后来发现是 GRUB 配置文件被改坏了。你想想看,Bootloader 阶段的日志非常有限,基本只能靠屏幕上的错误信息来判断。

GRUB2 的配置文件位置:

/boot/grub2/grub.cfg        # 主配置文件(不要手动编辑)
/etc/default/grub           # 用户可编辑的配置
grub2-mkconfig -o /boot/grub2/grub.cfg  # 重新生成配置

常见的 Bootloader 错误:

  • Error: No such partition —— 分区表变了,或者磁盘顺序变了
  • Error: File not found —— 内核文件或 initramfs 丢失
  • grub rescue> 提示符 —— GRUB 找不到配置文件,进入救援模式

避坑指南: 我曾经手贱直接编辑了 /boot/grub2/grub.cfg,结果重启后系统起不来。记住,永远通过 /etc/default/grub 修改,然后用 grub2-mkconfig 生成。这是血的教训。

第三阶段:内核加载阶段

Bootloader 把内核和 initramfs 加载到内存后,就把控制权交给了内核。内核开始解压自身,初始化硬件驱动,挂载根文件系统。

这个阶段的日志会输出到内核环形缓冲区(kernel ring buffer),你可以用 dmesg 命令查看。我个人习惯在排查启动问题时,第一时间看 dmesg | grep -i error

内核启动参数:

# 在 GRUB 启动时按 e 编辑,可以添加或修改参数
quiet           # 减少输出信息
verbose         # 输出详细信息
single          # 进入单用户模式
rd.break        # 在 initramfs 阶段中断,进入 shell

我印象最深的一次排查:一台新服务器启动到一半就重启了。用 dmesg 一看,发现是 ACPI 报错,内核 panic 了。后来加了 acpi=off 参数才启动成功。嗯,这其实是 BIOS 和内核的兼容性问题。

内核阶段的关键日志:

日志来源 查看命令 说明
内核环形缓冲区 dmesg 实时查看内核消息
系统日志 journalctl -k systemd 管理的内核日志
串口输出 console=ttyS0 通过串口捕获启动日志

我的经验: 如果系统完全起不来,可以在 GRUB 启动参数里加上 console=ttyS0,115200,然后用串口线连到另一台电脑上捕获日志。这样就能看到内核 panic 的完整信息了。

第四阶段:init 进程启动

内核挂载根文件系统后,会启动第一个用户空间进程 —— init。在传统 SysVinit 系统中,它是 /sbin/init。在现代系统中,它通常是 /lib/systemd/systemd

init 进程的 PID 永远是 1。它负责启动所有其他系统服务。说白了,它就是所有进程的祖宗。

SysVinit vs systemd:

特性 SysVinit systemd
启动方式 串行启动 并行启动
配置文件 /etc/inittab /etc/systemd/system/
日志管理 /var/log/messages journalctl
依赖管理 手动编写脚本 自动处理依赖

我曾经在 CentOS 6 上遇到过一个问题:某个服务启动失败,导致后续所有服务都卡住了。因为 SysVinit 是串行启动的,一个挂了后面全完蛋。换成 systemd 后,并行启动确实快了很多,但排查起来也更复杂了。

systemd 的启动分析工具:

# 查看启动耗时
systemd-analyze

# 查看每个服务的启动时间
systemd-analyze blame

# 查看启动过程中的关键事件
journalctl -b -p err

# 查看特定服务的启动日志
journalctl -u sshd.service

init 阶段常见问题:

  • 服务启动超时 —— 检查服务配置和网络依赖
  • 文件系统挂载失败 —— 检查 /etc/fstab
  • selinux 策略阻止 —— 查看 audit.log
  • 磁盘空间不足 —— 根分区满了,服务起不来

避坑指南: 我曾经在 /etc/fstab 里写错了一个挂载点,结果系统启动到一半就进入 emergency mode。记住,修改 fstab 前一定要备份,而且最好用 mount -a 先测试一下。

好了,四个阶段都讲完了。总结一下我的个人经验:

  • BIOS/UEFI 阶段 —— 看硬件指示灯和蜂鸣器
  • Bootloader 阶段 —— 看屏幕错误信息,进 rescue 模式修复
  • 内核加载阶段 —— 用 dmesg 或串口捕获日志
  • init 进程启动 —— 用 journalctl 和 systemd-analyze 分析

你想想看,启动流程就像一条流水线。每个环节都有它独特的日志特征。掌握了这些,下次遇到系统起不来的问题,你就知道该从哪里下手了。

公众号:蓝海资料掘金营,微信deep3321