一、启动总流程图
kernel和initrd: 探测硬件->加载驱动(initrd, 微型linux)->挂载根文件系统->rootfs(/sbin/init) 。initrd不是必须的。
二、三个主要的init
讲述三个主要的 Init 系统:sysvinit,UpStart 和 systemd
1、sysvinit
SysVinit 顺序运行(串行),概念简单清晰、启动慢。启动流程如下:
init--->inittab(runlevel)--->rc.sysinit(系统初始化)--->rc--->rcX.d(启停服务)--->rc.local--->tty和login
缺点:频繁地使用硬件热插拔技术,sysvinit需要默认就启动所有可能使用的硬件对应的服务;网络共享盘的挂载(nfs、iSCSI),需要netfs 服务来挂载所有这些网络盘;启动慢。
2、upstart
Upstart 采用事件驱动模型。更快地启动系统(并行);当新硬件被发现时动态启动服务;硬件被拔除时动态停止服务。
UpStart 主要的概念是 job 和 event。Job 就是一个工作单元,用来完成一件工作,比如启动一个后台服务,或者运行一个配置命令。每个 Job 都等待一个或多个事件,一旦事件发生,upstart 就触发该 job 完成相应的工作。
开机upstart首先产生startup事件。
3、systemd
systemd 的最大特点有两个:
(1)、提供了比 UpStart 更激进的并行启动能力,采用了 socket / D-Bus activation 等技术启动服务。结果就是:更快的启动速度。
(2)、用 CGroup 统计跟踪子进程,干净可靠。
3.1、并行化Socket
对于传统的 Unix daemon,彼此的真正依赖是服务所提供的 socket。
如果能尽早建立客户程序所必须的 socket 而令客户程序处于等待状态而不是在服务程序完全启动后再启动客户程序,我们就能加快启动进程,进一步并行化进程启动。
3.2、并行化Bus服务
Linux上现代的daemon都通过DBus而非socket来交互。
DBus已经提供了所有必要的hook:使用DBus将会在第一次访问时加载服务,并且给予最小的、每请求一个的、消费 者与生产者同时启动的同步机制。
例如Avahi与CUPS(CUPS需要Avahi进行 mDNS/DNS-SD上打印机扫描)同时启动,仅仅是简单的同时启动二者,若CUPS比Avahi启动快,则DBus将把请求缓存入队列,直到 Avahi服务进行了处理。
总结如下:基于Socket和基于DBus的服务可一次并行启动所有进程,无需任何额外的同步。基于激活的策略还能令我们进行延迟加载服务。 如果服务很少被用到,我们可以在第一次被访问时启动,而不是在启动过程中启动。
3.3、并行化文件系统任务
系统启动过程中,文件系统相关的活动是最耗时的,比如挂载文件系统,fsck,磁盘配额检查等。
Systemd 集成了 autofs 的实现,对于系统中的挂载点,比如/home,当系统启动的时候,systemd 为其创建一个临时的自动挂载点。在这个时刻/home 真正的挂载设备尚未启动好,真正的挂载操作还没有执行,文件系统检测也还没有完成。可是那些依赖该目录的进程已经可以并发启动,他们的 open()操作被内建在 systemd 中的 autofs 捕获,将该 open()调用挂起(可中断睡眠状态)。然后等待真正的挂载操作完成,文件系统检测也完成后,systemd 将该自动挂载点替换为真正的挂载点,并让 open()调用返回。由此,实现了那些依赖于文件系统的服务和文件系统本身同时并发启动。
3.3.1、三个init启动时间示意图
3.3.2、systemd设置运行级别:
systemd执行的第一个目标是default.target
获取当前的运行级别:systemctl get-default
设置:systemctl set-default multi-user.target
/lib/systemd/system/default.target -> graphical.target
3.3.3、systemd与sysvinit运行级别对应表
systemd 是一种新型init系统「译者注:每个操作系统都有一个启动程序,而Linux init是Linux系统操作中不可缺少的程序之一。所谓的init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。所以init始终是第一个进程(其进程编号始终为1)」,最早在Fedora中使用「译者注:据维基百科资料:http://en.wikipedia.org/wiki/Systemd#Adoption,最早使用 systemd 的是gentoo,最早使用并成为默认 init system 的是openSUSE。」,经过调整适应了其它许多发行版,例如RedHat、Suse和CentOS。
历史上,我们大部分人用过传统的SysV init 初始化脚本,它通常情况下在/etc/rc.d/init.d/文件夹下。这些脚本调用守护进程二进制代码,在后台fork一个进程。
尽管shell脚本非常的灵活,但是很难实现像superviseing(监管)进程和并行执行命令这样的任务。
通过对systemd的新式守护进程的介绍,我们发现systemd可以在runtime(运行时)更加简单的监管和控制守护进程,并且简化了监控的实现方式(implementation)。
systemctl命令是systemd团队一个非常好的首创。
这个命令能够显示更多的详细错误信息和包括启动错误在内的服务运行时错误。systemd引入了一个新术语:cgroups(控制组),它基本上是可被分层次安排的进程任务组。「译者注:这里简单介绍一下cgroup(control group)称为Containers,Containers着眼于资源的分配,利用configfs作配置。它有两个重要概念:第一是subsystem,内核可以给进程提供的服务/资源;第二是container,一个进程组,成员共享同样的一个或多个子系统分配限制。Containers是分层次的,一个container可以hold多个container。它的可取之处是创建了一个资源分配的框架,其它开发者可以利用这个框架去开发自己的资源分配patch,比如磁盘设备。」
如果仅仅通过原来的初始化系统,决定哪个进程是做什么的、属于哪个用户的变得越来越困难。
但是通过systemd,当一个进程派生其它进程时,这些子进程会被自动变成父进程控制组的成员,这样一来就可以避免继承的混乱。