1、Init进程起源:Unix System V Init的诞生背景与设计哲学
1.1 为什么需要Init?——从Unix的启动说起
你想想看,一台计算机按下电源键之后,到底发生了什么?
硬件自检、引导加载程序、内核加载……这些步骤之后,内核终于跑起来了。但内核本身只是个“调度员”,它需要有人来管理用户空间的各种服务——网络、登录、定时任务、打印服务等等。
这个“人”,就是Init进程。
Init是系统启动后第一个由内核启动的用户态进程,PID固定为1。它负责拉起所有其他进程,并监控它们的运行状态。说白了,Init就是所有进程的“老祖宗”。
核心要点:Init进程是Unix/Linux系统中所有用户态进程的祖先,PID=1,由内核直接启动。
1.2 Unix System V Init的诞生背景
上世纪70年代末到80年代初,Unix开始从实验室走向商业市场。AT&T的Unix System V版本逐渐成为主流。但有个问题一直没解决——不同Unix系统的启动方式五花八门,缺乏统一标准。
我记得在早期的BSD系统上,启动脚本就是一堆散落在/etc目录下的shell脚本,命名规则全凭个人喜好。有的叫rc.local,有的叫boot.sh,维护起来简直是一场噩梦。
System V Init的出现,就是为了解决这个混乱局面。它由AT&T的工程师设计,首次在Unix System V Release 3中引入,后来在SVR4中成熟定型。
它的设计目标很明确:
- 标准化:让所有Unix系统采用统一的启动流程
- 层次化:按运行级别组织服务,方便管理
- 可预测:启动顺序固定,依赖关系清晰
- 可维护:管理员能轻松添加、删除、调整服务
1.3 设计哲学:运行级别与脚本化
System V Init最核心的设计思想,就是运行级别(Runlevel)。
什么是运行级别?你可以把它理解成系统的“工作模式”。
| 运行级别 | 含义 | 典型用途 |
|---|---|---|
| 0 | 关机 | 系统停机 |
| 1 | 单用户模式 | 维护、修复系统 |
| 2 | 多用户模式(无网络) | 早期Unix的默认级别 |
| 3 | 多用户模式(有网络) | 服务器常用级别 |
| 4 | 用户自定义 | 预留 |
| 5 | 多用户模式(图形界面) | 桌面系统 |
| 6 | 重启 | 系统重启 |
每个运行级别对应一组服务。切换运行级别时,Init会停止旧级别的服务,启动新级别的服务。
这种设计有什么好处?我举个例子。有一次线上服务器需要做内核升级,我只需要切换到单用户模式(运行级别1),所有网络服务自动停止,文件系统也安全卸载。升级完成后,再切回运行级别3,一切恢复正常。整个过程干净利落。
1.4 脚本体系:/etc/rc.d 的奥秘
System V Init的服务管理,靠的是/etc/rc.d目录下的脚本体系。这个体系的结构非常精巧:
/etc/rc.d/
├── rc
├── rc.sysinit
├── rc.local
├── rc0.d/
├── rc1.d/
├── rc2.d/
├── rc3.d/
├── rc4.d/
├── rc5.d/
├── rc6.d/
└── init.d/
每个rcN.d目录(N是运行级别)里,存放的都是指向init.d中脚本的符号链接。这些链接的命名规则很有意思:
- S开头:Start,启动服务。例如
S10network - K开头:Kill,停止服务。例如
K90network - 数字:决定启动/停止的顺序。数字越小,越早执行
举个例子,在/etc/rc3.d/目录下,你可能会看到:
S10network -> ../init.d/network
S25sshd -> ../init.d/sshd
S55crond -> ../init.d/crond
S90httpd -> ../init.d/httpd
K01smartd -> ../init.d/smartd
这意味着进入运行级别3时,系统会先启动网络服务(S10),然后是SSH(S25)、定时任务(S55)、HTTP服务(S90),同时停止smartd(K01)。
避坑指南:我曾经在配置服务启动顺序时犯过一个低级错误——把数据库服务的启动顺序排在了网络服务之前。结果数据库启动时绑定IP失败,服务直接挂了。后来我养成了习惯:网络服务永远是S10,数据库服务至少S20以后。
1.5 Init进程的工作流程
系统启动时,Init进程的工作流程大致如下:
- 读取配置文件:
/etc/inittab,确定默认运行级别 - 执行系统初始化:运行
/etc/rc.d/rc.sysinit,挂载文件系统、设置主机名、激活交换分区等 - 进入默认运行级别:执行
/etc/rc.d/rc 3(假设默认级别是3) - 启动/停止服务:遍历
/etc/rc3.d/,按顺序执行脚本 - 启动终端:在虚拟终端上启动
getty,等待用户登录
这里有个细节值得注意——/etc/inittab文件。它定义了Init的行为:
# /etc/inittab
id:3:initdefault: # 默认运行级别为3
si::sysinit:/etc/rc.d/rc.sysinit # 系统初始化脚本
l0:0:wait:/etc/rc.d/rc 0 # 进入运行级别0
l1:1:wait:/etc/rc.d/rc 1 # 进入运行级别1
l3:3:wait:/etc/rc.d/rc 3 # 进入运行级别3
l6:6:wait:/etc/rc.d/rc 6 # 进入运行级别6
ca::ctrlaltdel:/sbin/shutdown -t3 -r now # Ctrl+Alt+Del处理
1:2345:respawn:/sbin/mingetty tty1 # 终端1
2:2345:respawn:/sbin/mingetty tty2 # 终端2
每一行的格式是:id:runlevels:action:process。其中action字段定义了Init如何处理这个进程——是等待它完成(wait),还是崩溃后自动重启(respawn),还是只执行一次(once)。
1.6 System V Init的优缺点
任何设计都有取舍。System V Init在当年是革命性的,但放到今天看,问题也不少。
优点:
- 概念简单,容易理解
- 脚本化,灵活性强
- 运行级别切换方便
- 经过几十年验证,稳定可靠
缺点:
- 串行启动,速度慢。所有服务按顺序一个一个来,不能并行
- 依赖关系靠人工维护。脚本里的数字顺序就是依赖顺序,但没人能保证不出错
- 缺乏自动化依赖解析。如果服务A依赖服务B,你得手动把A的数字设得比B大
- 热插拔设备支持差。USB设备插上后,Init不会自动处理
我印象很深的是,有一次在数据中心部署一批新服务器,每台机器要启动上百个服务。用System V Init,启动时间接近5分钟。后来换成systemd,同样的服务配置,启动时间缩短到40秒。这就是串行和并行的差距。
1.7 为什么还要学它?
你可能会问:现在都用systemd了,学这个老古董还有意义吗?
我的回答是:理解历史,才能更好地理解现在。
System V Init的设计哲学——运行级别、脚本化、顺序启动——深刻影响了后来的所有init系统。systemd虽然改进了很多,但它的target概念本质上就是运行级别的升级版。很多嵌入式系统、旧版Linux发行版、以及某些Unix变种,至今仍在使用System V Init。
更重要的是,当你遇到系统启动故障时,理解Init的工作方式能帮你快速定位问题。是脚本没执行?是依赖顺序错了?还是运行级别配置不对?这些知识在排障时非常有用。
注意:如果你在维护老系统(比如RHEL 5、CentOS 6、Debian 7及更早版本),System V Init仍然是默认的init系统。掌握它,就是掌握这些系统的命脉。
好了,这一章我们聊了Init的起源、System V Init的设计哲学、运行级别、脚本体系和工作流程。下一章,我们会深入/etc/inittab的每一行配置,看看Init到底是怎么工作的。