3. init系统演进

在定制 init 脚本实现系统快速启动的工程中,理解不同 init 系统的设计哲学与启动模型,是做出正确技术选型的前提。init 是内核启动后创建的第一个用户态进程(PID 1),它负责挂载文件系统、启动服务、管理运行级,并在系统关机时有序终止进程。从 1983 年的 SysV init 到今天的 systemd,init 系统经历了从“串行脚本”到“并行依赖图”再到“事件驱动”的演进。本节将横向对比五种主流 init 系统,帮助你在嵌入式、服务器、桌面等不同场景中选出最合适的方案。

核心原理:五种 init 的启动模型差异

SysV init 采用“运行级 + 串行脚本”模型。系统启动时按 /etc/rcX.d/ 目录下的 Snn 和 Knn 脚本顺序执行,每个脚本必须等待前一个完成。这种模型简单直观,但启动时间随服务数量线性增长,且无法表达服务间的真实依赖关系。

Upstart 由 Ubuntu 开发,采用“事件驱动 + 作业”模型。服务不再按固定顺序启动,而是由事件(如 started network)触发。它支持并行启动和依赖声明,但事件模型复杂,调试困难,最终被 systemd 取代。

systemd 采用“单元 + 依赖图 + 并行激活”模型。每个服务、挂载点、设备、套接字都是单元(unit),通过 Wants、Requires、After、Before 声明依赖。systemd 按依赖图并行启动,并支持套接字激活、按需启动、cgroup 资源控制,是现代 Linux 发行版的事实标准。

OpenRC 是 Gentoo 的 init 系统,采用“依赖树 + 并行”模型。它保留 Shell 脚本风格,但通过 depend 函数声明依赖,支持并行启动。OpenRC 不替代 PID 1,而是与 SysV init 或 BusyBox init 配合,适合喜欢脚本可控性的场景。

BusyBox init 是嵌入式领域的轻量方案,采用“inittab + 串行”模型。配置文件 /etc/inittab 定义 sysinit、respawn、once 等动作,代码量极小,启动逻辑简单,适合资源受限的嵌入式设备。

五种 init 系统启动模型对比 从串行脚本到并行依赖图,再到事件驱动 SysV init 运行级 + 串行脚本 rc0.d ~ rc6.d Snn/Knn 顺序执行 无依赖声明 启动时间线性增长 简单、兼容性好 Upstart 事件驱动 + 作业 start on / stop on 事件触发启动 支持并行 事件模型复杂 Ubuntu 旧版 systemd 单元 + 依赖图 + 并行 Wants/Requires/After 套接字激活 cgroup 资源控制 按需启动 现代发行版标准 OpenRC 依赖树 + 并行 depend() 声明 Shell 脚本风格 并行启动 不替代 PID 1 Gentoo/Alpine BusyBox init inittab + 串行 /etc/inittab sysinit/respawn 代码量极小 无依赖管理 嵌入式首选 启动速度慢 启动速度快 并行能力与依赖管理能力递增 → 老旧服务器 兼容性优先 Ubuntu 14.04 历史遗留系统 现代服务器/桌面 功能与速度兼顾 Gentoo/Alpine 脚本可控性优先 嵌入式设备 资源受限 选型决策要点: • 启动速度要求高 → systemd(并行依赖图)或 OpenRC(并行依赖树) • 资源极度受限 → BusyBox init(代码量最小,无依赖管理) • 需要脚本完全可控 → OpenRC 或 SysV init;需要现代特性 → systemd

方法流程:如何根据场景选择 init 系统

选择 init 系统时,建议按以下流程判断:

  1. 确定硬件资源:若内存小于 64MB、存储小于 128MB,优先 BusyBox init;若资源充足,进入下一步。
  2. 确定启动时间目标:若要求 5 秒内完成启动,选择 systemd 或 OpenRC 的并行模式;若可接受 15 秒以上,SysV init 也可用。
  3. 确定依赖复杂度:服务间存在网络、数据库、文件系统等复杂依赖时,systemd 的依赖图最清晰;简单线性依赖可用 OpenRC。
  4. 确定维护生态:需要长期维护、日志统一、资源隔离时,systemd 的 journald 和 cgroup 是明显优势。
  5. 确定团队熟悉度:若团队只熟悉 Shell 脚本,OpenRC 或 SysV init 的学习成本最低。

关键结论:没有“最好”的 init,只有“最合适”的 init。嵌入式选 BusyBox,现代服务器选 systemd,Gentoo/Alpine 选 OpenRC,老旧系统保留 SysV init,Upstart 仅用于维护历史系统。

案例场景:三种典型环境的 init 选型

场景一:工业网关(ARM Cortex-A7,256MB RAM,128MB Flash)。启动时间要求 8 秒内,服务包括网络、串口、Modbus、Web 配置。推荐 BusyBox init + 自定义 rcS 脚本,通过 /etc/inittab 定义 ::sysinit:/etc/init.d/rcS,在 rcS 中并行启动网络和串口服务。若需依赖管理,可升级为 OpenRC,但需评估 Flash 占用。

场景二:云服务器(x86_64,8GB RAM,SSD)。要求快速启动、日志集中、服务隔离。推荐 systemd,使用 systemctl enable 管理服务,通过 systemd-analyze blame 分析启动耗时,利用 After=network.target 声明依赖。典型配置如下:

[Unit]
Description=Custom Init Service
After=network.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/my-service
Restart=on-failure
MemoryLimit=256M

[Install]
WantedBy=multi-user.target

场景三:Alpine Linux 容器。镜像体积敏感,服务数量少。推荐 OpenRC,它默认集成在 Alpine 中,通过 rc-update add 添加服务,启动脚本位于 /etc/init.d/。OpenRC 的 depend() 函数可声明 need net、after firewall 等依赖,兼顾轻量与可控。

误区与复盘:常见选型错误

误区一:盲目追求 systemd。在 64MB 内存的嵌入式设备上强行运行 systemd,会导致启动缓慢甚至 OOM。systemd 本身依赖 dbus、cgroup、udev 等组件,资源开销不可忽视。

误区二:认为 BusyBox init 无法并行。BusyBox init 本身串行,但可在 rcS 脚本中用 & 后台启动服务,再用 wait 同步,实现有限并行。

误区三:忽略 Upstart 的维护状态。Upstart 已停止活跃开发,新项目不应选用,仅用于维护 Ubuntu 14.04 等历史系统。

误区四:OpenRC 与 SysV init 混淆。OpenRC 是 init 系统的服务管理框架,可运行在 SysV init 或 BusyBox init 之上,并非独立的 PID 1 实现。

五种 init 系统对比清单

特性 SysV init Upstart systemd OpenRC BusyBox init
启动模型 运行级+串行 事件驱动 依赖图+并行 依赖树+并行 inittab+串行
依赖声明 无 start on/stop on Wants/Requires/After depend() 无
并行启动 不支持 支持 支持 支持 不支持
资源占用 低 中 高 中低 极低
典型发行版 CentOS 6 Ubuntu 14.04 CentOS 7+/Ubuntu 16+ Gentoo/Alpine 嵌入式/OpenWrt
适用场景 老旧服务器 历史系统维护 现代服务器/桌面 轻量可控系统 资源受限设备