kexec 快速重启 Linux

其实 kexec 这个快速启动技术出来已经有好几年的时间了,被传地很神秘。快速内核“热”切换,这个字其实有着一定的误导性,导致不明真相的围观群众盲目崇拜。

先简单介绍一下 kexec

kexec (kernel execution) is a mechanism of the Linux kernel that allows "live" booting of a new kernel over the currently running one. kexec skips the bootloader stage (hardware initialization phase by the firmware or BIOS) and directly loads the new kernel into memory, which starts executing immediately. This avoids the long times associated with a full reboot, and is useful on systems with high availability requirements, where minimizing downtime is of essence.
kexec 是 Linux 内核的一个补丁,让您可以从当前正在运行的内核直接引导到一个新内核。在上面描述的引导序列中, kexec 跳过了整个引导装载程序阶段(第一部分)并直接跳转到我们希望引导到的内核。不再有硬件的重启,不再有固件操作,不再涉及引导装载程序。完全避开了引导序列中最弱的一环 -- 固件。这一功能部件带来的最大益处在于,系统现在可以极其快速地重新启动。对企业级系统而言, kexec 大大减少了重新启动引起的系统宕机时间。对内核和系统软件开发者而言, kexec 帮助您在开发和测试成果时可以迅速重新启动系统,而不必每次都要再经历耗时的固件阶段。

**kexec 的好处:要求高可用性的系统,以及需要不断重新启动系统的内核开发人员,都将受益于 kexec 。因为 kexec跳过了系统重新启动过程中最耗时的部分(也就是 POST - 固件初始化硬件设备的阶段),所以重新启动变得非常快,可用性得到了提高。 **

个人一直觉得这个技术是适合被应用在生产环境中的服务器上来减少重启所需要的时间,从而减少系统和整个 IT 基础架构的宕机时间,提高可用性。而在桌面个上,其意义并不是太大,因此一直没有去尝试。

今天趁着 Ubuntu Server 有内核升级的机会,就顺便体验了一把传说中的 kexec 快速启动。

两个测试环境
Ubuntu Server 9.10 Karmic Koala x86
Running kernel: 2.6.31-15-generic-pae
New kernel: 2.6.31-16-generic-pae

Debian GNU/Linux squeeze/sid x86
Running kernel: 2.6.30-2.686
New kernel: 2.6.30-2.686
你没看错我也没打错,同一个内核也可以,因为该系统上只留了一个内核,囧

kexec 工作需要先满足的两个条件

  1. kernel patch : 编译的时候得选上 CONFIG_KEXEC=y ,该选项会打开 kernel execution
    Debian sid , Ubuntu desktop 和 Ubuntu Server 的内核都已经开启该选项。
    这个命令可以用来确认内核是否包含 kexec / kdump 支持: egrep "KEXEC|CRASH|CAL_S|VMCORE" /boot/config-uname -a``
  2. userspace tool: 安装 kexec-tools 包

Debian GNU/Linux 和 Ubuntu , Ubuntu Server (所有命令均假设用户有 root 权限)
apt-get install kexec-tools

Arch Linux
pacman -S kexec-tools

使用 kexec

kexec 的执行过程包括两个步骤

  1. 在当前被使用的内核下,将要使用的新内核载入到内存中
  2. 重新启动到之前预先载入的新内核

第一步:加载新内核
kexec -l kernel-image --append=command-line-options --initrd=initrd-image

kernel-image:需要重启进入的那个新内核的内核文件
command-line-options:新内核启动时必须要传递给它的命令行参数,记住在不确定的情况下,传递/proc/cmdline (当前内核的启动参数)的内容总是最安全的

最后一个可选项 initrd:启动时用到的 initrd image 。

不确定的情况下 Ubuntu / Debian 可以用下面这一条命令:
kexec -l /boot/vmlinuz-$(uname -r) --append=$(cat /proc/cmdline) --initrd=/boot/initrd.img-$(uname -r)

更多信息请 RTFM :-D

第二步:载入完成之后”切换”到新内核
kexec -e

至于command-line-options,不同发行版有些出入,我就大胆假设一下能坚持看到这里的都能看明白:
Ubuntu Server
root=UUID=8850aec2-d10a-43b4-8c86-10c8d350a12e ro

全新安装的Ubuntu 9.10,GRUB2,LVM上是这样的鸟(我工作机上的)
BOOT_IMAGE=/vmlinuz-2.6.31-16-generic root=/dev/mapper/ubuntu-root ro

Debian squeeze/sid GRUB2
root=/dev/sda1

**测试结果
**1. Ubuntu Server
这个服务器跑的是文本模式,ssh到服务器载入新内核之后执行kexec -e。终端冻结无法再执行任何操作,可以看到服务器按照初始化相反的顺序关闭当前的系统:关闭进程,关闭系统服务,将 buffers 写回到文件系统,撤销交换分区的使用,unmount文件系统,重启。

可以注意到这次重启跳过了 bootloader 阶段,直接从内核阶段开始。这时候 Linux 内核获得对系统的控制权,它设置所需要的数据结构,侦测现有系统上的设备并载入所需的驱动程序,初始化这些设备,包括初始化和文件系统相关联的虚拟设备,如 LVM 或者 software RAID。启动过程中最后一个环节涉及到用户级别初始化,由内核执行 init(/sbin/init)完成。用户级别初始化阶段,内核检查文件系统的完整性,挂载 /etc/fstab 里列出的文件系统,激活交换分区(或者交换文件),启动系统服务,设置系统终端,并完成所有其他设置。

注意:测试了几次发现这么干有时候会导致服务器终端(显示器+键盘)无法操作,但是ssh过去还是可以正常操作的。不知是操作不当还是bug。

  1. Debian sid GDM 作为系统服务启动
    在 XFCE4 桌面下执行,桌面会冻结,无法进行任何操作。重启完成后会直接看到 GDM 登录窗口,很容易理解。

总结一下
其实所谓的内核”热”切换,归根结底还是一个系统重启,uptime归零,不同之处在于跳过了传统的 bootloader stage(包括hardware -> firmware/BIOS stage -> first level bootloader/MBR -> second level bootloader/GRUB ),直接进入了 kernel stage 。

很难说到底能节省多少时间,但是保守估计在不同的硬件上至少可以节省5-10秒的启动时间,甚至更多。

本文仓促中完成,若有不当之处,欢迎围观并指正。

参考及延伸阅读
http://docs.oracle.com/cd/E37670_01/E37355/html/ol_kexec.html
http://en.wikipedia.org/wiki/Kexec
Reboot Linux faster using kexec
使用 kexec 快速重启 Linux
Inside the Linux boot process
GRUB and the x86 Boot Process
Boot Process, Init, and Shutdown