近年來,
Linux
系統的
init
程序經歷了兩次重大的演進,傳統的
sysvinit
已經淡出歷史舞臺,新的
init
系統
UpStart
和
systemd
各有特點,而越來越多的
Linux
發行版採納了
systemd
。本文簡要介紹了這三種
init
系統的使用和原理,每個
Linux
系統管理員和系統軟體開發者都應該瞭解它們,以便更好地管理系統和開發應用。
Linux初始化init系統
1。 init 系統簡單介紹
Linux 作業系統的啟動首先從 BIOS 開始,接下來進入 boot loader,由 bootloader 載入核心,進行核心初始化。核心初始化的最後一步就是啟動 pid 為 1 的 init 程序,這個程序是系統的第一個程序,它負責產生其他所有使用者程序。
init 的一些特點
init
以守護程序方式存在,是所有其他程序的祖先。
init
程序非常獨特,能夠完成其他程序無法完成的任務。
init
系統能夠定義、管理和控制
init
程序的行為。它負責組織和執行許多獨立的或相關的始化工作(因此被稱為
init
系統),從而讓計算機系統進入某種使用者預訂的執行模式。
僅僅將核心執行起來是毫無實際用途的,必須由
init
系統將系統代入可操作狀態。比如啟動外殼
shell
後,便有了人機互動,這樣就可以讓計算機執行一些預訂程式完成有實際意義的任務。
init 的歷史及發展
大多數
Linux
發行版的
init
系統是和
System V
相相容的,被稱為
sysvinit
。這是人們最熟悉的
init
系統。一些發行版如 Slackware 採用的是 BSD 風格 Init 系統,這種風格使用較少,本文不再涉及。其他的發行版如 Gentoo 是自己定製的。Ubuntu 和 RHEL 採用
upstart
替代了傳統的 sysvinit。而 Fedora 從版本 15 開始使用了一個被稱為
systemd
的新 init 系統。
在 Linux 主要應用於
伺服器
和
PC
機的時代,SysVinit 執行非常良好,概念簡單清晰。它主要依賴於 Shell 指令碼,這就決定了它的
最大弱點:啟動太慢
。在很少重新啟動的 Server 上,這個缺點並不重要。而當 Linux 被應用到移動終端裝置的時候,啟動慢就成了一個大問題。為了更快地啟動,人們開始改進 sysvinit,先後出現了
upstart
和
systemd
這兩個主要的新一代 init 系統。Upstart 已經開發了 8 年多,在不少系統中已經替換 sysvinit。
Systemd
出現較晚,但發展更快,大有取代 upstart 的趨勢。
2。 sysvinit 的特點和使用
sysvinit
就是
system V
風格
的 init 系統,顧名思義,它源於 System V 系列 UNIX。它提供了比
BSD
風格
init 系統更高的靈活性。是已經風行了幾十年的
UNIX init
系統,一直被各類 Linux 發行版所採用。
2。1 sysvinit 執行級別
Sysvinit 用術語
runlevel
來定義預訂的執行模式
Sysvinit 檢查
/etc/inittab
檔案中是否含有
initdefault
項
這告訴
init
系統是否有一個預設執行模式,如果沒有預設的執行模式,那麼使用者將進入系統控制檯,手動決定進入何種執行模式
cat /etc/inittab# Default runlevel。 The runlevels used are:# 0 - halt (Do NOT set initdefault to this)# 1 - Single user mode# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)# 3 - Full multiuser mode# 4 - unused# 5 - X11# 6 - reboot (Do NOT set initdefault to this)id:3:initdefault:
2。2 sysvinit 執行順序
Sysvinit 巧妙地用指令碼、檔案命名規則和軟連結來實現不同的 runlevel 級別。
第一步
首先,
sysvinit
需要讀取
/etc/inittab
檔案
分析這個檔案的內容,它獲得以下一些配置資訊
系統需要進入的
runlevel
捕獲組合鍵的定義
定義電源
fail/restore
指令碼
啟動
getty
和
虛擬控制檯
第二步
得到配置資訊後,
sysvinit
順序地執行以下這些步驟,從而將系統初始化為預訂的
runlevel X
/etc/rc。d/rc。sysinit
/etc/rc。d/rc
和
/etc/rc。d/rcX。d/
(X 代表執行級別 0-6)
/etc/rc。d/rc。local
X Display Manager
(如果需要的話)
執行第二步解析
-
/etc/rc。d/rc。sysinit
首先,執行
rc。sysinit
以便執行一些重要的系統初始化任務
在 RedHat 公司的 RHEL5 中(RHEL6 已經使用
upstart
了),
rc。sysinit
主要完成以下這些工作
啟用
udev
和
selinux
設定定義在
/etc/sysctl。conf
中的核心引數
設定
系統時鐘
載入
keymaps
使能
交換分割槽
設定主機名(
hostname
)
根
分割槽檢查
和
remount
啟用
RAID
和
LVM
裝置
開啟
磁碟配額
檢查並掛載所有
檔案系統
清除過期的
locks
和
PID
檔案
/etc/rc.d/rc 和/etc/rc.d/rcX.d/
完成了以上這些工作之後,
sysvinit
開始執行
/etc/rc。d/rc
指令碼
根據不同的
runlevel
,
rc 指令碼
將開啟對應該
runlevel
的
rcX。d
目錄(
X
就是
runlevel
),找到並執行存放在該目錄下的所有啟動指令碼
每個
runlevel X
都有一個這樣的目錄,目錄名為
/etc/rc。d/rcX。d
在
/etc/rc。d/rcX。d
存放著很多不同的指令碼
檔名以
S
開頭的指令碼就是啟動時應該執行的指令碼,
S
後面跟的數字定義了這些指令碼的執行順序
檔名以
K
開頭的指令碼就是啟動時應該關閉的指令碼,
K
後面跟的數字定義了這些指令碼的執行順序
在
/etc/rc。d/rcX。d
目錄下的指令碼其實都是一些軟連結檔案,真實的指令碼檔案存放在
/etc/init。d
目錄下
# ll /etc/rc5。d/lrwxrwxrwx 1 root root 16 Sep 4 2008 K02dhcdbd -> 。。/init。d/dhcdbd。。。。(中間省略)。。。。lrwxrwxrwx 1 root root 14 Sep 4 2008 K91capi -> 。。/init。d/capilrwxrwxrwx 1 root root 23 Sep 4 2008 S00microcode_ctl -> 。。/init。d/microcode_ctllrwxrwxrwx 1 root root 22 Sep 4 2008 S02lvm2-monitor -> 。。/init。d/lvm2-monitor。。。。(中間省略)。。。。lrwxrwxrwx 1 root root 17 Sep 4 2008 S10network -> 。。/init。d/network。。。。(中間省略)。。。。lrwxrwxrwx 1 root root 11 Sep 4 2008 S99local -> 。。/rc。locallrwxrwxrwx 1 root root 16 Sep 4 2008 S99smartd -> 。。/init。d/smartd。。。。(底下省略)。。。。
/etc/rc.d/rc.local
當所有的初始化指令碼執行完畢,
sysvinit
執行
/etc/rc。d/rc。local
指令碼
rc。local
是
Linux
留給使用者進行個性化設定的地方
可以把自己私人想設定和啟動的東西放到這裡,一臺
Linux Server
的使用者一般不止一個,所以才有這樣的考慮
2。3 sysvinit 系統關閉
Sysvinit
不僅需要負責初始化系統,還需要負責關閉系統。在系統關閉時,為了保證資料的一致性,需要小心地按順序進行結束和清理工作。
比如應該先停止對檔案系統有讀寫操作的服務,然後再
umount
檔案系統。否則資料就會丟失。
這種順序的控制這也是依靠
/etc/rc。d/rcX。d/
目錄下所有指令碼的命名規則來控制的,在該目錄下所有以
K
開頭的指令碼都將在關閉系統時呼叫,字母
K
之後的數字定義了它們的執行順序。
這些指令碼負責安全地停止服務或者其他的關閉工作。
2。4 sysvinit 管理控制
此外,在系統啟動之後,管理員還需要對已經啟動的程序進行管理和控制。原始的
sysvinit
軟體包包含了一系列的控制啟動,執行和關閉所有其他程式的工具。
halt
停止系統
init
這個就是
sysvinit
本身的
init
程序實體,以
pid1
身份執行,是所有使用者程序的父程序,最主要的作用是在啟動過程中使用
/etc/inittab
檔案建立程序
killall5
就是
SystemV
的
killall
命令,向除自己的會話(session)程序之外的其它程序發出訊號,所以不能殺死當前使用的
shell
last
回溯
/var/log/wtmp
檔案(或者
-f
選項指定的檔案),顯示自從這個檔案建立以來,所有使用者的登入情況
lastb
作用和
last
差不多,預設情況下使用
/var/log/btmp
檔案,顯示所有失敗登入企圖
mesg
控制其它使用者對使用者終端的訪問
pidof
找出程式的程序識別號(
pid
),輸出到標準輸出裝置
poweroff
等於
shutdown -h –p
,或者
telinit 0
,關閉系統並切斷電源
reboot
等於
shutdown –r
或者
telinit 6
,重啟系統
runlevel
讀取系統的登入記錄檔案(一般是
/var/run/utmp
)把以前和當前的系統執行級輸出到標準輸出裝置
shutdown
以一種安全的方式終止系統,所有正在登入的使用者都會收到系統將要終止通知,並且不準新的登入
sulogin
當系統進入單使用者模式時,被
init
呼叫,當接收到啟動載入程式傳遞的
-b
選項時,
init
也會呼叫
sulogin
telinit
實際是
init
的一個連線,用來向
init
傳送單字元引數和訊號
utmpdump
以一種使用者友好的格式向標準輸出裝置顯示
/var/run/utmp
檔案的內容
wall
向所有有資訊許可權的登入使用者傳送訊息
不同的 Linux 發行版在這些
sysvinit
的基本工具基礎上又開發了一些輔助工具用來簡化
init
系統的管理工作。比如 RedHat 的 RHEL 在 sysvinit 的基礎上開發了
initscripts
軟體包,包含了大量的啟動指令碼 (如
rc。sysinit
) ,還提供了
service
,
chkconfig
等命令列工具,甚至一套圖形化介面來管理 init 系統。其他的 Linux 發行版也有各自的
initscript
或其他名字的
init
軟體包來簡化
sysvinit
的管理。
只要您理解了
sysvinit
的機制,在一個最簡的僅有
sysvinit
的系統下,您也可以直接呼叫指令碼啟動和停止服務,手動建立
inittab
和建立軟連線來完成這些任務。因此理解
sysvinit
的基本原理和命令是最重要的。您甚至也可以開發自己的一套管理工具。
2。5 sysvinit 小結
sysvinit 的優點是概念簡單
Service
開發人員只需要編寫啟動和停止指令碼,
概念非常清楚
將
service
新增/刪除到某個
runlevel
時,只需要執行一些建立/刪除軟連線檔案的
基本操作
這些都
不需要
學習額外的知識或特殊的定義語法(
UpStart
和
Systemd
都需要使用者學習新的定義系統初始化行為的語言)
sysvinit
的另一個重要優點是
確定的執行順序
指令碼嚴格按照啟動數字的大小順序執行,一個執行完畢再執行下一個,這非常有益於錯誤排查
UpStart
和
systemd
支援併發啟動,導致沒有人可以確定地瞭解具體的啟動順序,排錯不易
但是序列地執行指令碼導致
sysvinit
執行效率較慢,在新的
IT
環境下,啟動快慢成為一個重要問題
此外動態裝置載入等
Linux
新特性也暴露出
sysvinit
設計的一些問題
針對這些問題,人們開始想辦法改進
sysvinit
,以便加快啟動時間,並解決
sysvinit
自身的設計問題
3。 UpStart 的特點和使用
假如您使用的 Linux 發行版是 Ubuntu,很可能會發現在您的計算機上找不到/etc/inittab 檔案了,這是因為 Ubuntu 使用了一種被稱為 upstart 的新型 init 系統。
3。1 Upstart 簡介
開發Upstart的緣由
在
2.6 核心
支援下,一旦新外設連線到系統,核心便可以自動實時地發現它們,並初始化這些裝置,進而使用它們。這為行動式裝置使用者提供了很大的靈活性。
可是這些特性為
sysvinit
帶來了一些挑戰。當系統初始化時,需要被初始化的裝置並沒有連線到系統上;比如印表機。為了管理列印任務,系統需要啟動
CUPS
等服務,而如果印表機沒有接入系統的情況下,啟動這些服務就是一種浪費。
Sysvinit
沒有辦法處理這類需求,它必須一次性把所有可能用到的服務都啟動起來,即使印表機並沒有連線到系統,
CUPS
服務也必須啟動。
還有網路共享盤的掛載問題。在
/etc/fstab
中,可以指定系統自動掛載一個網路盤,比如
NFS
,或者
iSCSI
裝置。在本文的第一部分
sysvinit
的簡介中可以看到,
sysvinit
分析
/etc/fstab
掛載檔案系統這個步驟是在網路啟動之前。可是如果網路沒有啟動,
NFS
或者
iSCSI
都不可訪問,當然也無法進行掛載操作。
Sysvinit
採用
netdev
的方式來解決這個問題,即
/etc/fstab
發現
netdev
屬性掛載點的時候,不嘗試掛載它,在網路初始化並使能之後,還有一個專門的
netfs
服務來掛載所有這些網路盤。這是一個不得已的補救方法,給管理員帶來不便。部分新手管理員甚至從來也沒有聽說過
netdev
選項,因此經常成為系統管理的一個陷阱。
針對以上種種情況,
Ubuntu
開發人員在評估了當時的幾個可選
init
系統之後,決定重新設計和開發一個全新的
init
系統,即
UpStart
。
UpStart
基於事件機制,比如
U 盤
插入
USB
介面後,
udev
得到核心通知,發現該裝置,這就是一個新的事件。
UpStart
在感知到該事件之後觸發相應的等待任務,比如處理
/etc/fstab
中存在的掛載點。採用這種
事件驅動的模式
,
upstart
完美地解決了即插即用裝置帶來的新問題。
此外,採用事件驅動機制也帶來了一些其它有益的變化,比如加快了系統啟動時間。
sysvinit
執行時是同步阻塞的。一個指令碼執行的時候,後續指令碼必須等待。這意味著所有的初始化步驟都是序列執行的,而實際上很多服務彼此並不相關,完全可以並行啟動,從而減小系統的啟動時間。在
Linux
大量應用於伺服器的時代,系統啟動時間也許還不那麼重要;然而對於桌面系統和行動式裝置,啟動時間的長短對使用者體驗影響很大。此外雲計算等新的
Server
端技術也往往需要單個裝置可以更加快速地啟動。
使用Upstart 的特點
UpStart
解決了之前提到的 sysvinit 的缺點。採用
事件驅動模型
,UpStart 可以:
更快地啟動系統
當新硬體被發現時動態啟動服務
硬體被拔除時動態停止服務
3。2 Upstart 概念和術語
Upstart
的基本概念和設計清晰明確。UpStart 主要的概念是
job
和 **
event
**。
Job
就是一個工作單元,用來完成一件工作,比如啟動一個後臺服務,或者執行一個配置命令。
每個
Job
都等待一個或多個
事件
,一旦事件發生,
upstart
就觸發該
job
完成相應的工作。
3。2。1 Job 介紹
Job
就是一個工作的單元,一個任務或者一個服務。可以理解為
sysvinit
中的一個服務指令碼
有三種類型的工作
task job
task job
代表在一定時間內會執行完畢的任務,比如刪除一個檔案
service job
service job
代表後臺服務程序,比如
apache httpd
這裡程序一般不會退出,一旦開始執行就成為一個後臺精靈程序,由
init
程序管理,如果這類程序退出,由
init
程序重新啟動,它們只能由
init
程序傳送訊號停止它們的停止一般也是由於所依賴的停止事件而觸發的,不過
upstart
也提供命令列工具,讓管理人員手動停止某個服務
abstract job
abstract job
僅由
upstart
內部使用,僅對理解 upstart 內部機理有所幫助。我們不用關心它。除了以上的分類之外,還有另一種工作(Job)分類方法。Upstart 不僅可以用來為整個系統的初始化服務,也可以為每個使用者會話(session)的初始化服務。系統的初始化任務就叫做
system job
,比如掛載檔案系統的任務就是一個 system job;使用者會話的初始化服務就叫做
session job
。
3。2。2 Job 生命週期
Upstart
為每個工作都維護一個生命週期。一般來說,工作有開始,執行和結束這幾種狀態。為了更精細地描述工作的變化,Upstart 還引入了一些其它的狀態。
比如開始就有開始之前(
pre-start
),即將開始(
starting
)和已經開始了(
started
)幾種不同的狀態,這樣可以更加精確地描述工作的當前狀態。
工作從某種初始狀態開始,逐漸變化,或許要經歷其它幾種不同的狀態,最終進入另外一種狀態,形成一個狀態機。在這個過程中,當工作的狀態即將發生變化的時候,
init
程序會發出相應的事件(
event
)。
Linux初始化init系統
Linux初始化init系統
其中有四個狀態會引起
init
程序傳送相應的事件,表明該工作的相應變化:
Starting
Started
Stopping
Stopped
3。2。3 事件 Event
顧名思義,
Event
就是一個事件。事件在 upstart 中以通知訊息的形式具體存在。一旦某個事件發生了,
Upstart
就向整個系統傳送一個訊息。沒有任何手段阻止事件訊息被 upstart 的其它部分知曉,也就是說,事件一旦發生,整個
upstart
系統中所有工作和其它的事件都會得到通知。
Event 可以分為三類: signal,methods 或者 hooks
Signals
Signal
事件是非阻塞的,非同步的,傳送一個訊號之後控制權立即返回
Methods
Methods
事件是阻塞的,同步的
Hooks
Hooks
事件是阻塞的,同步的,它介於 Signals 和 Methods 之間,呼叫發出 Hooks 事件的程序必須等待事件完成才可以得到控制權,但不檢查事件是否成功
事件是個非常抽象的概念
下面我羅列出一些常見的事件,希望可以幫助您進一步瞭解事件的含義:
系統上電啟動,init 程序會發送”start”事件
根檔案系統可寫時,相應 job 會發送檔案系統就緒的事件
一個塊裝置被發現並初始化完成,傳送相應的事件
某個檔案系統被掛載,傳送相應的事件
類似 atd 和 cron,可以在某個時間點,或者週期的時間點發送事件
另外一個 job 開始或結束時,傳送相應的事件
一個磁碟檔案被修改時,可以發出相應的事件
一個網路裝置被發現時,可以發出相應的事件
預設路由被新增或刪除時,可以發出相應的事件
3。2。4 Job 和 Event 的相互協作
Upstart
就是由事件觸發工作執行的一個系統,每一個程式的執行都由其依賴的事件發生而觸發的。
系統初始化的過程是在工作和事件的相互協作下完成的
,可以大致描述如下:
系統初始化時,init 程序開始執行,init 程序自身會發出不同的事件,這些最初的事件會觸發一些工作執行。
每個工作執行過程中會釋放不同的事件,這些事件又將觸發新的工作執行。
如此反覆,直到整個系統正常執行起來。
工作配置檔案
任何一個工作都是由一個工作配置檔案(
Job Configuration File
)定義的。這個檔案是一個文字檔案,包含一個或者多個小節(
stanza
)。每個小節是一個完整的定義模組,定義了工作的一個方面,比如 author 小節定義了工作的作者。工作配置檔案存放在
/etc/init
下面,是以
。conf
作為檔案字尾的檔案。
# 一個最簡單的工作配置檔案#This is a simple demo of Job Configure file#This line is comment, start with ##Stanza 1, The authorauthor “Liu Ming”#Stanza 2, Descriptiondescription “This job only has author and description, so no use, just a demo”
上面的例子不會產生任何作用,一個真正的工作配置檔案會包含很多小節,其中比較重要的小節有以下幾個。
expect Stanza
Upstart 除了負責系統的啟動過程之外,和 SysVinit 一樣,Upstart 還提供一系列的管理工具。當系統啟動之後,管理員可能還需要進行維護和調整,比如啟動或者停止某項系統服務。或者將系統切換到其它的工作狀態,比如改變執行級別。本文後續將詳細介紹
Upstart 的管理工具
的使用。
為了啟動,停止,重啟和查詢某個系統服務。Upstart 需要跟蹤該服務所對應的程序。比如
httpd
服務的程序 PID 為 1000。當用戶需要查詢 httpd 服務是否正常執行時,Upstart 就可以利用 ps 命令查詢程序 1000,假如它還在正常執行,則表明服務正常。當用戶需要停止 httpd 服務時,Upstart 就使用
kill
命令終止該程序。為此,**
Upstart
必須跟蹤服務程序的程序號**。
部分服務程序為了將自己變成
後臺精靈程序
(
daemon
),會採用兩次派生(
fork
)的技術,另外一些服務則不會這樣做。假如一個服務派生了兩次,那麼 UpStart 必須採用第二個派生出來的程序號作為服務的 PID。但是,UpStart 本身無法判斷服務程序是否會派生兩次,為此在定義該服務的工作配置檔案中必須寫明
expect
小節,告訴 UpStart 程序是否會派生兩次。
Expect
有兩種,
expect fork
表示程序只會
fork 一次
;
expect daemonize
表示程序會
fork 兩次
。
exec Stanza 和 script Stanza
一個 UpStart 工作一定需要做些什麼,可能是執行一條 shell 命令,或者執行一段指令碼。用”
exec
“關鍵字配置工作需要執行的命令;用”
script
“關鍵字定義需要執行的指令碼。
# 顯示了 exec 和 script 的用法# script 例子# mountall。confdescription “Mount filesystems on boot”start on startupstop on starting rcS。。。script 。 /etc/default/rcS [ -f /forcefsck ] && force_fsck=”——force-fsck” [ “$FSCKFIX”=”yes” ] && fsck_fix=”——fsck-fix” 。。。 exec mountall –daemon $force_fsck $fsck_fixend script。。。
這是
mountall
的例子,該工作在系統啟動時執行,負責掛載所有的檔案系統。該工作需要執行復雜的指令碼,由”
script
“關鍵字定義;在指令碼中,使用了
exec
來執行
mountall
命令。
`start on Stanza 和 stop on Stanza
“
start on
“定義了觸發工作的所有事件。”start on”的語法很簡單,如下所示:
start on EVENT [[KEY=]VALUE]。。。 [and|or。。。]
EVENT
表示事件的名字,可以在 start on 中指定多個事件,表示該工作的開始需要依賴多個事件發生。多個事件之間可以用 and 或者 or 組合,”表示全部都必須發生”或者”其中之一發生即可”等不同的依賴條件。除了事件發生之外,工作的啟動還可以依賴特定的條件,因此在 start on 的 EVENT 之後,可以用 KEY=VALUE 來表示額外的條件,一般是某個環境變數(KEY)和特定值(VALUE)進行比較。如果只有一個變數,或者變數的順序已知,則 KEY 可以省略。
“stop on”和”start on”非常類似,只不過是定義工作在什麼情況下需要停止。
# start on/ stop on 例子#dbus。confdescription “D-Bus system message bus”start on local-filesystemsstop on deconfiguring-networking……
D-Bus
是一個系統訊息服務,上面的配置檔案表明當系統發出
local-filesystems
事件時啟動 D-Bus;當系統發出
deconfiguring-networking
事件時,停止 D-Bus 服務。
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
。
# 傳統 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
之後的會話初始化過程。
# 採用 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 | : | : : :
3。3 UpStart 使用
本文僅列出了少數工作配置檔案的語法。要全面掌握工作配置檔案的寫法,需要詳細閱讀
Upstart
的
手冊
。這裡讓我們來分析一下如何用
Upstart
來實現傳統的執行級別,進而瞭解如何靈活使用工作配置檔案。
3。3。1 系統執行級別
Upstart 的運作完全是基於工作和事件的。工作的狀態變化和執行會引起事件,進而觸發其它工作和事件。
而傳統的 Linux 系統初始化是基於執行級別的,即 SysVInit。因為歷史的原因,Linux 上的多數軟體還是採用傳統的 SysVInit 指令碼啟動方式,並沒有為 UpStart 開發新的啟動指令碼,因此即便在 Debian 和 Ubuntu 系統上,還是必須模擬老的 SysVInit 的執行級別模式,以便和多數現有軟體相容。
雖然 Upstart 本身並沒有執行級別的概念,但完全可以用 UpStart 的工作模擬出來。讓我們完整地考察一下 UpStart 機制下的系統啟動過程。
3。3。2 系統啟動過程
下圖描述了 UpStart 的啟動過程
Linux初始化init系統
系統上電後執行
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
非常類似。
3。3。3 開發注意事項
作為程式開發人員,在編寫系統服務時,需要了解 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
訊號。
3。3。4 Upstart 命令
作為系統管理員,一個重要的職責就是管理系統服務。比如系統服務的監控,啟動,停止和配置。UpStart 提供了一系列的命令來完成這些工作。其中的核心是**
initctl
**,這是一個帶子命令風格的命令列工具。
# 可以用 initctl list 來檢視所有工作的概況:# initctl listalsa-mixer-save stop/waitingavahi-daemon start/running, process 690mountall-net stop/waitingrc stop/waitingrsyslog start/running, process 482screen-cleanup stop/waitingtty4 start/running, process 859udev start/running, process 334upstart-udev-bridge start/running, process 304ureadahead-other stop/waiting
這是在
Ubuntu10。10
系統上的輸出,其它的 Linux 發行版上的輸出會有所不同。第一列是工作名,比如
rsyslog
。第二列是工作的目標;第三列是工作的狀態。
initctl stop
停止一個正在執行的工作
initctl start
開始一個工作
initctl status
來檢視一個工作的狀態
initctl restart
重啟一個工作
initctl reload
可以讓一個正在執行的服務重新載入配置檔案
這些命令和傳統的
service
命令十分相似
Linux初始化init系統
文章作者:
Escape
文章連結:
https://www。escapelife。site/posts/4fb48da7。html