浅析Linux初始化init系统(2):UpStart
作者:网络转载 发布时间:[ 2015/10/20 13:46:02 ] 推荐标签:操作系统
Session Init
UpStart 还可以用于管理用户会话的初始化。在我写这篇文章的,多数 Linux 发行版还没有使用 UpStart 管理会话。只有在 Ubuntu Raring 版本中,使用 UpStart 管理用户会话的初始化过程。 首先让我们了解一下 Session 的概念。Session 是一个用户会话,即用户从远程或者本地登入系统开始工作,直到用户退出。这整个过程构成一个会话。 每个用户的使用习惯和使用方法都不相同,因此用户往往需要为自己的会话做一个定制,比如添加特定的命令别名,启动特殊的应用程序或者服务,等等。这些工作都属于对特定会话的初始化操作,因此可以被称为 Session Init。 用户使用 Linux 可以有两种模式:字符模式和图形界面。在字符模式下,会话初始化相对简单。用户登录后只能启动一个 Shell,通过 shell 命令使用系统。各种 shell 程序都支持一个自动运行的启动脚本,比如~/.bashrc。用户在这些脚本中加入需要运行的定制化命令。字符会话需求简单,因此这种现有的机制工作的很好。 在图形界面下,事情变得复杂一些。用户登录后看到的并不是一个 shell 提示符,而是一个桌面。一个完整的桌面环境由很多组件组成。 一个桌面环境包括 window manager,panel 以及其它一些定义在/usr/share/gnome-session/sessions/下面的基本组件;此外还有一些辅助的应用程序,共同帮助构成一个完整的方便的桌面,比如 system monitors,panel applets,NetworkManager,Bluetooth,printers 等。当用户登录之后,这些组件都需要被初始化,这个过程比字符界面要复杂的多。目前启动各种图形组件和应用的工作由 gnome-session 完成。过程如下: 以 Ubuntu 为例,当用户登录 Ubuntu 图形界面后,显示管理器(Display Manager)lightDM 启动 Xsession。Xsession 接着启动 gnome-session,gnome-session 负责其它的初始化工作,然后开始了一个 desktop session。
图 2.传统 desktop session 启动过程
init
|- lightdm
| |- Xorg
| |- lightdm ---session-child
| |- gnome-session --session=ubuntu
| |- compiz
| |- gwibber
| |- nautilus
| |- nm-applet
| :
| :
|
|- dbus-daemon --session
|
:
:
这个过程有一些缺点(和 sysVInit 类似)。一些应用和组件其实并不需要在会话初始化过程中启动,更好的选择是在需要它们的时候才启动。比如 update-notifier 服务,该服务不停地监测几个文件系统路径,一旦这些路径上发现可以更新的软件包,提醒用户。这些文件系统路径包括新插入的 DVD 盘等。Update-notifier 由 gnome-session 启动并一直运行着,在多数情况下,用户并不会插入新的 DVD,此时 update-notifier 服务一直在后台运行并消耗系统资源。更好的模式是当用户插入 DVD 的时候再运行 update-notifier。这样可以加快启动时间,减小系统运行过程中的内存等系统资源的开销。对于移动,嵌入式等设备等这还意味着省电。除了 Update-notifier 服务之外,还有其它一些类似的服务。比如 Network Manager,之内用户很少切换网络设备,所以大部分时间 Network Manager 服务仅仅是在浪费系统资源;再比如 backup manager 等其它常驻内存,后台不间断运行却很少真正被使用的服务。 用 UpStart 的基于事件的按需启动的模式可以很好地解决这些问题,比如用户插入网线的时候才启动 Network Manager,因为用户插入网线表明需要使用网络,这可以被称为按需启动。 下图描述了采用 UpStart 之后的会话初始化过程。
图 3.采用 Upstart 的 Desktop session init 过程
init
|- lightdm
| |- Xorg
| |- lightdm ---session-child
| |- session-init
# <-- upstart running as normal user
| |- dbus-daemon --session
| |- gnome-session --session=ubuntu
| |- compiz
| |- gwibber
| |- nautilus
| |- nm-applet
| :
| :
:
:
UpStart 使用
有两种人员需要了解 Upstart 的使用。第一类是系统开发人员,比如 MySQL 的开发人员。它们需要了解如何编写工作配置文件,以便用 UpStart 来管理服务。比如启动,停止 MySQL 服务。 另外一种情况是系统管理员,它们需要掌握 Upstart 的管理命令以便配置和管理系统的初始化,管理系统服务。
系统开发人员需要了解的 UpStart 知识
系统开发人员不仅需要掌握工作配置文件的写法,还需要了解一些针对服务进程编程上的要求。本文仅列出了少数工作配置文件的语法。要全面掌握工作配置文件的写法,需要详细阅读 Upstart 的手册。这里让我们来分析一下如何用 Upstart 来实现传统的运行级别,进而了解如何灵活使用工作配置文件。 Upstart 系统中的运行级别 Upstart 的运作完全是基于工作和事件的。工作的状态变化和运行会引起事件,进而触发其它工作和事件。 而传统的 Linux 系统初始化是基于运行级别的,即 SysVInit。因为历史的原因,Linux 上的多数软件还是采用传统的 SysVInit 脚本启动方式,并没有为 UpStart 开发新的启动脚本,因此即便在 Debian 和 Ubuntu 系统上,还是必须模拟老的 SysVInit 的运行级别模式,以便和多数现有软件兼容。 虽然 Upstart 本身并没有运行级别的概念,但完全可以用 UpStart 的工作模拟出来。让我们完整地考察一下 UpStart 机制下的系统启动过程。 系统启动过程 下图描述了 UpStart 的启动过程。
图 4.UpStart 启动过程
image004 系统上电后运行 GRUB 载入内核。内核执行硬件初始化和内核自身初始化。在内核初始化的后,内核将启动 pid 为 1 的 init 进程,即 UpStart 进程。 Upstart 进程在执行了一些自身的初始化工作后,立即发出”startup”事件。上图中用红色方框加红色箭头表示事件,可以在左上方看到”startup”事件。 所有依赖于”startup”事件的工作被触发,其中重要的是 mountall。mountall 任务负责挂载系统中需要使用的文件系统,完成相应工作后,mountall 任务会发出以下事件:local-filesystem,virtual-filesystem,all-swaps, 其中 virtual-filesystem 事件触发 udev 任务开始工作。任务 udev 触发 upstart-udev-bridge 的工作。Upstart-udev-bridge 会发出 net-device-up IFACE=lo 事件,表示本地回环 IP 网络已经准备绪。同时,任务 mountall 继续执行,终会发出 filesystem 事件。 此时,任务 rc-sysinit 会被触发,因为 rc-sysinit 的 start on 条件如下:
start on filesystem and net-device-up IFACE=lo
任务 rc-sysinit 调用 telinit。Telinit 任务会发出 runlevel 事件,触发执行/etc/init/rc.conf。 rc.conf 执行/etc/rc$.d/目录下的所有脚本,和 SysVInit 非常类似,读者可以参考本文第一部分的描述。 程序开发时需要注意的事项 作为程序开发人员,在编写系统服务时,需要了解 UpStart 的一些特殊要求。只有符合这些要求的软件才可以被 UpStart 管理。 规则一,派生次数需声明。 很多 Linux 后台服务都通过派生两次的技巧将自己变成后台服务程序。如果您编写的服务也采用了这个技术,必须通过文档或其它的某种方式明确地让 UpStart 的维护人员知道这一点,这将影响 UpStart 的 expect stanza,我们在前面已经详细介绍过这个 stanza 的含义。 规则二,派生后即可用。 后台程序在完成第二次派生的时候,必须保证服务已经可用。因为 UpStart 通过派生计数来决定服务是否处于绪状态。 规则三,遵守 SIGHUP 的要求。 UpStart 会给精灵进程发送 SIGHUP 信号,此时,UpStart 希望该精灵进程做以下这些响应工作: ?完成所有必要的重新初始化工作,比如重新读取配置文件。这是因为 UpStart 的命令”initctl reload”被设计为可以让服务在不重启的情况下更新配置。 ?精灵进程必须继续使用现有的 PID,即收到 SIGHUP 时不能调用 fork。如果服务必须在这里调用 fork,则等同于派生两次,参考上面的规则一的处理。这个规则保证了 UpStart 可以继续使用 PID 管理本服务。 规则四,收到 SIGTEM 即 shutdown。 ?当收到 SIGTERM 信号后,UpStart 希望精灵进程进程立即干净地退出,释放所有资源。如果一个进程在收到 SIGTERM 信号后不退出,Upstart 将对其发送 SIGKILL 信号。
系统管理员需要了解的 Upstart 命令
作为系统管理员,一个重要的职责是管理系统服务。比如系统服务的监控,启动,停止和配置。UpStart 提供了一系列的命令来完成这些工作。其中的核心是initctl,这是一个带子命令风格的命令行工具。 比如可以用 initctl list 来查看所有工作的概况:
$initctl list
alsa-mixer-save stop/waiting
avahi-daemon start/running, process 690
mountall-net stop/waiting
rc stop/waiting
rsyslog start/running, process 482
screen-cleanup stop/waiting
tty4 start/running, process 859
udev start/running, process 334
upstart-udev-bridge start/running, process 304
ureadahead-other stop/waiting
这是在 Ubuntu10.10 系统上的输出,其它的 Linux 发行版上的输出会有所不同。第一列是工作名,比如 rsyslog。第二列是工作的目标;第三列是工作的状态。 此外还可以用 initctl stop 停止一个正在运行的工作;用 initctl start 开始一个工作;还可以用 initctl status 来查看一个工作的状态;initctl restart 重启一个工作;initctl reload 可以让一个正在运行的服务重新载入配置文件。这些命令和传统的 service 命令十分相似。
表 2.service 命令和 initctl 命令对照表
很多情况下管理员并不喜欢子命令风格,因为需要手动键入的字符太多。UpStart 还提供了一些快捷命令来简化 initctl,实际上这些命令只是在内部调用相应的 initctl 命令。比如 reload,restart,start,stop 等等。启动一个服务可以简单地调用
start <job>
这和执行 initctl start <job>是一样的效果。 一些命令是为了兼容其它系统(主要是 sysvinit),比如显示 runlevel 用/sbin/runlevel 命令:
$runlevel
N 2
这个输出说明当前系统的运行级别为 2。而且系统没有之前的运行级别,也是说在系统上电启动进入预定运行级别之后没有再修改过运行级别。 那么如何修改系统上电之后的默认运行级别呢? 在 Upstart 系统中,需要修改/etc/init/rc-sysinti.conf 中的 DEFAULT_RUNLEVEL 这个参数,以便修改默认启动运行级别。这一点和 sysvinit 的习惯有所不同,大家需要格外留意。 还有一些随 UpStart 发布的小工具,用来帮助开发 UpStart 或者诊断 UpStart 的问题。比如 init-checkconf 和 upstart-monitor 还可以使用 initctl 的 emit 命令从命令行发送一个事件。
#initctl emit <event>
这一般是用于 UpStart 本身的排错。
Upstart 小结
可以看到,UpStart 的设计比 SysVInit 更加先进。多数 Linux 发行版上已经不再使用 SysVInit,一部分发行版采用了 UpStart,比如 Ubuntu;而另外一些比如 Fedora,采用了一种被称为 systemd 的 init 系统。Systemd 出现的比 UpStart 更晚,但发展迅速,虽然 UpStart 也还在积极开发并被越来越多地应用,但 systemd 似乎发展更快,我将在下一篇文章中再介绍 systemd。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11