SystemD是Linux下的一種init軟件,由Lennart Poettering帶頭開(kāi)發(fā),并在LGPL 2.1及其后續(xù)版本許可證下開(kāi)源發(fā)布。Lennart是redhat員工,但SystemD不是redhat項(xiàng)目。其開(kāi)發(fā)目標(biāo)是提供更優(yōu)秀的框架以表示系統(tǒng)服務(wù)間的依賴關(guān)系,并依此實(shí)現(xiàn)系統(tǒng)初始化時(shí)服務(wù)的并行啟動(dòng),同時(shí)達(dá)到降低Shell的系統(tǒng)開(kāi)銷(xiāo)的效果,最終代替現(xiàn)在常用的System V與BSD風(fēng)格init程序。
SystemD這一名字源于Unix中的一個(gè)慣例:在Unix中常以“d”作為系統(tǒng)守護(hù)進(jìn)程(英語(yǔ):daemon,亦稱后臺(tái)進(jìn)程)的后綴標(biāo)識(shí)。除此以外,SystemD亦是借代英文術(shù)語(yǔ)D體系,而這一術(shù)語(yǔ)即是用于描述一個(gè)人具有快速地適應(yīng)環(huán)境并解決困難的能力。
SystemD被設(shè)計(jì)用來(lái)改進(jìn)SysVinit的缺點(diǎn),與Ubuntu的upstart形成技術(shù)競(jìng)爭(zhēng)。SystemD的很多概念來(lái)源于蘋(píng)果的launchd。目標(biāo)是盡可能啟動(dòng)更少進(jìn)程;盡可能將更多進(jìn)程并行啟動(dòng)(這是性能優(yōu)于SysVinit的理念基礎(chǔ))。SystemD盡可能減少對(duì)Shell腳本的依賴。傳統(tǒng)SysVinit使用inittab來(lái)決定運(yùn)行哪些Shell腳本,大量使用Shell腳本被認(rèn)為是效率低下無(wú)法并行的原因。SystemD使用了Linux專屬技術(shù),不再顧及POSIX兼容,只要能滿足社會(huì)變革的需要,突破一些可能過(guò)時(shí)的技術(shù)約束,這也是當(dāng)今創(chuàng)信理念的需要,相信市場(chǎng)會(huì)給出評(píng)判。
與多數(shù)發(fā)行版使用的System V風(fēng)格init相比,SystemD采用了以下新技術(shù):
采用Socket激活式與總線激活式服務(wù),以提高相互依賴的各服務(wù)的并行運(yùn)行性能;
用cgroups代替PID來(lái)追蹤進(jìn)程,因此即使是兩次fork之后生成的守護(hù)進(jìn)程也不會(huì)脫離systemd的控制。
從設(shè)計(jì)構(gòu)思上說(shuō),由于SystemD使用了cgroup與fanotify等組件以實(shí)現(xiàn)其特性,所以只適用于Linux。有鑒于此,基于kFreeBSD分支的軟件源無(wú)法納入SystemD。
大多數(shù)主流發(fā)行版要么已經(jīng)采用 Systemd,要么即將在下個(gè)發(fā)布中采用(如 Debian 和 Ubuntu)。在本教程中,我們使用 Fedora 21(該發(fā)行版已經(jīng)是 Systemd 的優(yōu)秀實(shí)驗(yàn)場(chǎng)地)的一個(gè)預(yù)覽版進(jìn)行演示,但不論您用哪個(gè)發(fā)行版,要用到的命令和注意事項(xiàng)都應(yīng)該是一樣的。這是 Systemd 的一個(gè)加分點(diǎn):它消除了不同發(fā)行版之間許多細(xì)微且瑣碎的區(qū)別。
在終端中輸入 ps ax | grep systemd,看到第一行,其中的數(shù)字 1 表示它的進(jìn)程號(hào)是1,也就是說(shuō)它是 Linux 內(nèi)核發(fā)起的第一個(gè)程序。因此,內(nèi)核一旦檢測(cè)完硬件并組織好了內(nèi)存,就會(huì)運(yùn)行 /usr/lib/systemd/systemd 可執(zhí)行程序,這個(gè)程序會(huì)按順序依次發(fā)起其他程序。(在還沒(méi)有 Systemd 的日子里,內(nèi)核會(huì)去運(yùn)行 /sbin/init,隨后這個(gè)程序會(huì)在名為 SysVinit 的系統(tǒng)中運(yùn)行其余的各種啟動(dòng)腳本。)
Systemd 的核心是一個(gè)叫單元 unit的概念,它是一些存有關(guān)于服務(wù)service(在運(yùn)行在后臺(tái)的程序)、設(shè)備、掛載點(diǎn)、和操作系統(tǒng)其他方面信息的配置文件。Systemd 的其中一個(gè)目標(biāo)就是簡(jiǎn)化這些事物之間的相互作用,因此如果你有程序需要在某個(gè)掛載點(diǎn)被創(chuàng)建或某個(gè)設(shè)備被接入后開(kāi)始運(yùn)行,Systemd 可以讓這一切正常運(yùn)作起來(lái)變得相當(dāng)容易。(在沒(méi)有 Systemd 的日子里,要使用腳本來(lái)把這些事情調(diào)配好,那可是相當(dāng)丑陋的。)要列出您 Linux 系統(tǒng)上的所有單元,輸入以下命令:
systemctl list-unit-files
現(xiàn)在,systemctl 是與 Systemd 交互的主要工具,它有不少選項(xiàng)。在單元列表中,您會(huì)注意到這兒有一些格式化:被使能enabled的單元顯示為綠色,被禁用disabled的顯示為紅色。標(biāo)記為“static”的單元不能直接啟用,它們是其他單元所依賴的對(duì)象。若要限制輸出列表只包含服務(wù),使用以下命令:
systemctl list-unit-files --type=service
注意,一個(gè)單元顯示為“enabled”,并不等于對(duì)應(yīng)的服務(wù)正在運(yùn)行,而只能說(shuō)明它可以被開(kāi)啟。要獲得某個(gè)特定服務(wù)的信息,以 GDM (Gnome Display Manager) 為例,輸入以下命令:
systemctl status gdm.service
這條命令提供了許多有用的信息:一段給人看的服務(wù)描述、單元配置文件的位置、啟動(dòng)的時(shí)間、進(jìn)程號(hào),以及它所從屬的 CGroups(用以限制各組進(jìn)程的資源開(kāi)銷(xiāo))。
如果您去查看位于 /usr/lib/systemd/system/gdm.service 的單元配置文件,您可以看到各種選項(xiàng),包括要被運(yùn)行的二進(jìn)制文件(“ExecStart”那一行),相沖突的其他單元(即不能同時(shí)進(jìn)入運(yùn)行的單元),以及需要在本單元執(zhí)行前進(jìn)入運(yùn)行的單元(“After”那一行)。一些單元有附加的依賴選項(xiàng),例如“Requires”(必要的依賴)和“Wants”(可選的依賴)。
此處另一個(gè)有趣的選項(xiàng)是:
Alias=display-manager.service
當(dāng)您啟動(dòng) gdm.service 后,您將可以通過(guò) systemctl status display-manager.service 來(lái)查看它的狀態(tài)。當(dāng)您知道有顯示管理程序 display manager在運(yùn)行并想對(duì)它做點(diǎn)什么,但您不關(guān)心那究竟是 GDM,KDM,XDM 還是什么別的顯示管理程序時(shí),這個(gè)選項(xiàng)會(huì)非常有用。
“目標(biāo)target”鎖定
如果您在 /usr/lib/systemd/system 目錄中輸入 ls 命令,您將看到各種以 .target 結(jié)尾的文件。啟動(dòng)目標(biāo) target是一種將多個(gè)單元聚合在一起以致于將它們同時(shí)啟動(dòng)的方式。例如,對(duì)大多數(shù)類(lèi) Unix 操作系統(tǒng)而言有一種“多用戶multi-user”狀態(tài),意思是系統(tǒng)已被成功啟動(dòng),后臺(tái)服務(wù)正在運(yùn)行,并且已準(zhǔn)備好讓一個(gè)或多個(gè)用戶登錄并工作——至少在文本模式下。(其他狀態(tài)包括用于進(jìn)行管理工作的單用戶single-user狀態(tài),以及用于機(jī)器關(guān)機(jī)的重啟reboot狀態(tài)。)
如果您打開(kāi) multi-user.target 文件一探究竟,您可能期待看到的是一個(gè)要被啟動(dòng)的單元列表。但您會(huì)發(fā)現(xiàn)這個(gè)文件內(nèi)部幾乎空空如也——其實(shí),一個(gè)服務(wù)會(huì)通過(guò) WantedBy 選項(xiàng)讓自己成為啟動(dòng)目標(biāo)的依賴。因此如果您去打開(kāi) avahi-daemon.service, NetworkManager.service 及其他 .service 文件看看,您將在 Install 段看到這一行:
WantedBy=multi-user.target
因此,切換到多用戶啟動(dòng)目標(biāo)會(huì)使能enable那些包含上述語(yǔ)句的單元。還有其他一些啟動(dòng)目標(biāo)可用(例如 emergency.target 提供一個(gè)緊急情況使用的 shell,以及 halt.target 用于機(jī)器關(guān)機(jī)),您可以用以下方式輕松地在它們之間切換:
systemctl isolate emergency.target
在許多方面,這些都很像 SysVinit 中的運(yùn)行級(jí) runlevel,如文本模式的 multi-user.target 類(lèi)似于第3運(yùn)行級(jí),graphical.target 類(lèi)似于第5運(yùn)行級(jí),reboot.target 類(lèi)似于第6運(yùn)行級(jí),諸如此類(lèi)。
開(kāi)啟與停止
現(xiàn)在您也許陷入了沉思:我們已經(jīng)看了這么多,但仍沒(méi)看到如何停止和開(kāi)啟服務(wù)!這其實(shí)是有原因的。從外部看,Systemd 也許很復(fù)雜,像野獸一般難以駕馭。因此在您開(kāi)始擺弄它之前,有必要從宏觀的角度看看它是如何工作的。實(shí)際用來(lái)管理服務(wù)的命令非常簡(jiǎn)單:
systemctl stop cups.service
systemctl start cups.service
(若某個(gè)單元被禁用了,您可以先通過(guò) systemctl enable 加上該單元名的方式將其使能。這種做法會(huì)為該單元?jiǎng)?chuàng)建一個(gè)符號(hào)鏈接,并將其放置在當(dāng)前啟動(dòng)目標(biāo)的 .wants 目錄下,這些 .wants 目錄在/etc/systemd/system 文件夾中。)
還有兩個(gè)有用的命令是 systemctl restart 和 systemctl reload,后面接單元名。后者用于讓單元重新加載它的配置文件。Systemd 的絕大部分都有良好的文檔,因此您可以查看手冊(cè) (man systemctl) 了解每條命令的細(xì)節(jié)。
定時(shí)器單元:取代 Cron
除了系統(tǒng)初始化和服務(wù)管理,Systemd 還染指了其他方面。在很大程度上,它能夠完成 cron 的工作,而且可以說(shuō)是以更靈活的方式(并帶有更易讀的語(yǔ)法)。cron 是一個(gè)以規(guī)定時(shí)間間隔執(zhí)行任務(wù)的程序——例如清除臨時(shí)文件,刷新緩存等。
如果您再次進(jìn)入 /usr/lib/systemd/system 目錄,您會(huì)看到那兒有多個(gè) .timer 文件。用 less 來(lái)查看這些文件,您會(huì)發(fā)現(xiàn)它們與 .service 和 .target 文件有著相似的結(jié)構(gòu),而區(qū)別在于 [Timer] 段。舉個(gè)例子:
[Timer]
OnBootSec=1h
OnUnitActiveSec=1w
OnBootSec 選項(xiàng)告訴 Systemd 在系統(tǒng)啟動(dòng)一小時(shí)后啟動(dòng)這個(gè)單元。第二個(gè)選項(xiàng)的意思是:自那以后每周啟動(dòng)這個(gè)單元一次。關(guān)于定時(shí)器有大量選項(xiàng)您可以設(shè)置,輸入 man systemd.time 查看完整列表。
Systemd 的時(shí)間精度默認(rèn)為一分鐘。也就是說(shuō),它會(huì)在設(shè)定時(shí)刻的一分鐘內(nèi)運(yùn)行單元,但不一定精確到那一秒。這么做是基于電源管理方面的原因,但如果您需要一個(gè)沒(méi)有任何延時(shí)且精確到毫秒的定時(shí)器,您可以添加以下一行:
AccuracySec=1us
另外, WakeSystem 選項(xiàng)(可以被設(shè)置為 true 或 false)決定了定時(shí)器是否可以喚醒處于休眠狀態(tài)的機(jī)器。
日志文件:向 journald 問(wèn)聲好
Systemd 的第二個(gè)主要部分是 journal 。這是個(gè)日志系統(tǒng),類(lèi)似于 syslog 但也有些顯著區(qū)別。如果您是個(gè) Unix 日志管理模式的粉絲,準(zhǔn)備好出離憤怒吧:這是個(gè)二進(jìn)制日志,因此您不能使用常規(guī)的命令行文本處理工具來(lái)解析它。這個(gè)設(shè)計(jì)決定不出意料地在網(wǎng)上引起了激烈的爭(zhēng)論,但它的確有些優(yōu)點(diǎn)。例如,日志可以被更系統(tǒng)地組織,帶有更多的元數(shù)據(jù),因此可以更容易地根據(jù)可執(zhí)行文件名和進(jìn)程號(hào)等過(guò)濾出信息。
要查看整個(gè) journal,輸入以下命令:
journalctl
像許多其他的 Systemd 命令一樣,該命令將輸出通過(guò)管道的方式引向 less 程序,因此您可以使用空格鍵向下滾動(dòng),鍵入/(斜杠)查找,以及其他熟悉的快捷鍵。您也能在此看到少許顏色,像紅色的警告及錯(cuò)誤信息。
以上命令會(huì)輸出很多信息。為了限制其只輸出本次啟動(dòng)的消息,使用如下命令:
journalctl -b
這就是 Systemd 大放異彩的地方!您想查看自上次啟動(dòng)以來(lái)的全部消息嗎?試試 journalctl -b -1 吧。再上一次的?用 -2 替換 -1 吧。那自某個(gè)具體時(shí)間,例如2014年10月24日16:38以來(lái)的呢?
journalctl -b --since=”2014-10-24 16:38”
即便您對(duì)二進(jìn)制日志感到遺憾,那依然是個(gè)有用的特性,并且對(duì)許多系統(tǒng)管理員來(lái)說(shuō),構(gòu)建類(lèi)似的過(guò)濾器比起寫(xiě)正則表達(dá)式而言容易多了。
我們已經(jīng)可以根據(jù)特定的時(shí)間來(lái)準(zhǔn)確查找日志了,那可以根據(jù)特定程序嗎?對(duì)單元而言,試試這個(gè):
journalctl -u gdm.service
(注意:這是個(gè)查看 X server 產(chǎn)生的日志的好辦法。)那根據(jù)特定的進(jìn)程號(hào)?
journalctl _PID=890
您甚至可以請(qǐng)求只看某個(gè)可執(zhí)行文件產(chǎn)生的消息:
journalctl /usr/bin/pulseaudio
若您想將輸出的消息限制在某個(gè)優(yōu)先級(jí),可以使用 -p 選項(xiàng)。該選項(xiàng)參數(shù)為 0 的話只會(huì)顯示緊急消息(也就是說(shuō),是時(shí)候向 $DEITY 祈求保佑了)(LCTT 譯注: $DEITY 是一個(gè)計(jì)算機(jī)方面的幽默,DEITY 是指廣義上的“神”,$前綴表示這是一個(gè)變量),為 7 的話會(huì)顯示所有消息,包括調(diào)試消息。請(qǐng)查看手冊(cè) (man journalctl) 獲取更多關(guān)于優(yōu)先級(jí)的信息。
值得指出的是,您也可以將多個(gè)選項(xiàng)結(jié)合在一起,若想查看在當(dāng)前啟動(dòng)中由 GDM 服務(wù)輸出的優(yōu)先級(jí)數(shù)小于等于 3 的消息,請(qǐng)使用下述命令:
journalctl -u gdm.service -p 3 -b
最后,如果您僅僅想打開(kāi)一個(gè)隨 journal 持續(xù)更新的終端窗口,就像在沒(méi)有 Systemd 時(shí)使用 tail 命令實(shí)現(xiàn)的那樣,輸入 journalctl -f 就好了。
沒(méi)有 Systemd 的生活?
如果您就是完全不能接受 Systemd,您仍然有一些主流發(fā)行版中的選擇。尤其是 Slackware,作為歷史最為悠久的發(fā)行版,目前還沒(méi)有做出改變,但它的主要開(kāi)發(fā)者并沒(méi)有將其從未來(lái)規(guī)劃中移除。一些不出名的發(fā)行版也在堅(jiān)持使用 SysVinit 。
但這又將持續(xù)多久呢?Gnome 正越來(lái)越依賴于 Systemd,其他的主流桌面環(huán)境也會(huì)步其后塵。這也是引起 BSD 社區(qū)一陣恐慌的原因:Systemd 與 Linux 內(nèi)核緊密相連,導(dǎo)致在某種程度上,桌面環(huán)境正變得越來(lái)越不可移植。一種折衷的解決方案也許會(huì)以 Uselessd (http://uselessd.darknedgy.net) 的形式到來(lái):一種裁剪版的 Systemd,純粹專注于啟動(dòng)和監(jiān)控進(jìn)程,而不消耗整個(gè)基礎(chǔ)系統(tǒng)。