轉自:http://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html, 少有改動(dòng)。
| Sysvinit 運行級別 | Systemd 目標 | 備注 |
|---|---|---|
| 0 | runlevel0.target, poweroff.target | 關(guān)閉系統。 |
| 1, s, single | runlevel1.target, rescue.target | 單用戶(hù)模式。 |
| 2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用戶(hù)定義/域特定運行級別。默認等同于 3。 |
| 3 | runlevel3.target, multi-user.target | 多用戶(hù),非圖形化。用戶(hù)可以通過(guò)多個(gè)控制臺或網(wǎng)絡(luò )登錄。 |
| 5 | runlevel5.target, graphical.target | 多用戶(hù),圖形化。通常為所有運行級別 3 的服務(wù)外加圖形化登錄。 |
| 6 | runlevel6.target, reboot.target | 重啟 |
| emergency | emergency.target | 緊急 Shell |
如前所述,在 Systemd 中,所有的服務(wù)都并發(fā)啟動(dòng),比如 Avahi、D-Bus、livirtd、X11、HAL 可以同時(shí)啟動(dòng)。乍一看,這似乎有點(diǎn)兒?jiǎn)?wèn)題,比如 Avahi 需要 syslog 的服務(wù),Avahi 和 syslog 同時(shí)啟動(dòng),假設 Avahi 的啟動(dòng)比較快,所以 syslog 還沒(méi)有準備好,可是 Avahi 又需要記錄日志,這豈不是會(huì )出現問(wèn)題?
Systemd 的開(kāi)發(fā)人員仔細研究了服務(wù)之間相互依賴(lài)的本質(zhì)問(wèn)題,發(fā)現所謂依賴(lài)可以分為三個(gè)具體的類(lèi)型,而每一個(gè)類(lèi)型實(shí)際上都可以通過(guò)相應的技術(shù)解除依賴(lài)關(guān)系。
絕大多數的服務(wù)依賴(lài)是套接字依賴(lài)。比如服務(wù) A 通過(guò)一個(gè)套接字端口 S1 提供自己的服務(wù),其他的服務(wù)如果需要服務(wù) A,則需要連接 S1。因此如果服務(wù) A 尚未啟動(dòng),S1 就不存在,其他的服務(wù)就會(huì )得到啟動(dòng)錯誤。所以傳統地,人們需要先啟動(dòng)服務(wù) A,等待它進(jìn)入就緒狀態(tài),再啟動(dòng)其他需要它的服務(wù)。Systemd 認為,只要我們預先把 S1 建立好,那么其他所有的服務(wù)就可以同時(shí)啟動(dòng)而無(wú)需等待服務(wù) A 來(lái)創(chuàng )建 S1 了。如果服務(wù) A 尚未啟動(dòng),那么其他進(jìn)程向 S1 發(fā)送的服務(wù)請求實(shí)際上會(huì )被 Linux 操作系統緩存,其他進(jìn)程會(huì )在這個(gè)請求的地方等待。一旦服務(wù) A 啟動(dòng)就緒,就可以立即處理緩存的請求,一切都開(kāi)始正常運行。
那么服務(wù)如何使用由 init 進(jìn)程創(chuàng )建的套接字呢?
Linux 操作系統有一個(gè)特性,當進(jìn)程調用 fork 或者 exec 創(chuàng )建子進(jìn)程之后,所有在父進(jìn)程中被打開(kāi)的文件句柄 (file descriptor) 都被子進(jìn)程所繼承。套接字也是一種文件句柄,進(jìn)程 A 可以創(chuàng )建一個(gè)套接字,此后當進(jìn)程 A 調用 exec 啟動(dòng)一個(gè)新的子進(jìn)程時(shí),只要確保該套接字的 close_on_exec 標志位被清空,那么新的子進(jìn)程就可以繼承這個(gè)套接字。子進(jìn)程看到的套接字和父進(jìn)程創(chuàng )建的套接字是同一個(gè)系統套接字,就仿佛這個(gè)套接字是子進(jìn)程自己創(chuàng )建的一樣,沒(méi)有任何區別。
這個(gè)特性以前被一個(gè)叫做 inetd 的系統服務(wù)所利用。Inetd 進(jìn)程會(huì )負責監控一些常用套接字端口,比如 Telnet,當該端口有連接請求時(shí),inetd 才啟動(dòng) telnetd 進(jìn)程,并把有連接的套接字傳遞給新的 telnetd 進(jìn)程進(jìn)行處理。這樣,當系統沒(méi)有 telnet 客戶(hù)端連接時(shí),就不需要啟動(dòng) telnetd 進(jìn)程。Inetd 可以代理很多的網(wǎng)絡(luò )服務(wù),這樣就可以節約很多的系統負載和內存資源,只有當有真正的連接請求時(shí)才啟動(dòng)相應服務(wù),并把套接字傳遞給相應的服務(wù)進(jìn)程。
和 inetd 類(lèi)似,systemd 是所有其他進(jìn)程的父進(jìn)程,它可以先建立所有需要的套接字,然后在調用 exec 的時(shí)候將該套接字傳遞給新的服務(wù)進(jìn)程,而新進(jìn)程直接使用該套接字進(jìn)行服務(wù)即可。
D-Bus 是 desktop-bus 的簡(jiǎn)稱(chēng),是一個(gè)低延遲、低開(kāi)銷(xiāo)、高可用性的進(jìn)程間通信機制。它越來(lái)越多地用于應用程序之間通信,也用于應用程序和操作系統內核之間的通信。很多現代的服務(wù)進(jìn)程都使用D-Bus 取代套接字作為進(jìn)程間通信機制,對外提供服務(wù)。比如簡(jiǎn)化 Linux 網(wǎng)絡(luò )配置的 NetworkManager 服務(wù)就使用 D-Bus 和其他的應用程序或者服務(wù)進(jìn)行交互:郵件客戶(hù)端軟件 evolution 可以通過(guò) D-Bus 從 NetworkManager 服務(wù)獲取網(wǎng)絡(luò )狀態(tài)的改變,以便做出相應的處理。
D-Bus 支持所謂"bus activation"功能。如果服務(wù) A 需要使用服務(wù) B 的 D-Bus 服務(wù),而服務(wù) B 并沒(méi)有運行,則 D-Bus 可以在服務(wù) A 請求服務(wù) B 的 D-Bus 時(shí)自動(dòng)啟動(dòng)服務(wù) B。而服務(wù) A 發(fā)出的請求會(huì )被 D-Bus 緩存,服務(wù) A 會(huì )等待服務(wù) B 啟動(dòng)就緒。利用這個(gè)特性,依賴(lài) D-Bus 的服務(wù)就可以實(shí)現并行啟動(dòng)。
系統啟動(dòng)過(guò)程中,文件系統相關(guān)的活動(dòng)是最耗時(shí)的,比如掛載文件系統,對文件系統進(jìn)行磁盤(pán)檢查(fsck),磁盤(pán)配額檢查等都是非常耗時(shí)的操作。在等待這些工作完成的同時(shí),系統處于空閑狀態(tài)。那些想使用文件系統的服務(wù)似乎必須等待文件系統初始化完成才可以啟動(dòng)。但是 systemd 發(fā)現這種依賴(lài)也是可以避免的。
Systemd 參考了 autofs 的設計思路,使得依賴(lài)文件系統的服務(wù)和文件系統本身初始化兩者可以并發(fā)工作。autofs 可以監測到某個(gè)文件系統掛載點(diǎn)真正被訪(fǎng)問(wèn)到的時(shí)候才觸發(fā)掛載操作,這是通過(guò)內核 automounter 模塊的支持而實(shí)現的。比如一個(gè) open()系統調用作用在"/misc/cd/file1"的時(shí)候,/misc/cd 尚未執行掛載操作,此時(shí) open()調用被掛起等待,Linux 內核通知 autofs,autofs 執行掛載。這時(shí)候,控制權返回給 open()系統調用,并正常打開(kāi)文件。
Systemd 集成了 autofs 的實(shí)現,對于系統中的掛載點(diǎn),比如/home,當系統啟動(dòng)的時(shí)候,systemd 為其創(chuàng )建一個(gè)臨時(shí)的自動(dòng)掛載點(diǎn)。在這個(gè)時(shí)刻/home 真正的掛載設備尚未啟動(dòng)好,真正的掛載操作還沒(méi)有執行,文件系統檢測也還沒(méi)有完成??墒悄切┮蕾?lài)該目錄的進(jìn)程已經(jīng)可以并發(fā)啟動(dòng),他們的 open()操作被內建在 systemd 中的 autofs 捕獲,將該 open()調用掛起(可中斷睡眠狀態(tài))。然后等待真正的掛載操作完成,文件系統檢測也完成后,systemd 將該自動(dòng)掛載點(diǎn)替換為真正的掛載點(diǎn),并讓 open()調用返回。由此,實(shí)現了那些依賴(lài)于文件系統的服務(wù)和文件系統本身同時(shí)并發(fā)啟動(dòng)。
當然對于"/"根目錄的依賴(lài)實(shí)際上一定還是要串行執行,因為 systemd 自己也存放在/之下,必須等待系統根目錄掛載檢查好。
不過(guò)對于類(lèi)似/home 等掛載點(diǎn),這種并發(fā)可以提高系統的啟動(dòng)速度,尤其是當/home 是遠程的 NFS 節點(diǎn),或者是加密盤(pán)等,需要耗費較長(cháng)的時(shí)間才可以準備就緒的情況下,因為并發(fā)啟動(dòng),這段時(shí)間內,系統并不是完全無(wú)事可做,而是可以利用這段空余時(shí)間做更多的啟動(dòng)進(jìn)程的事情,總的來(lái)說(shuō)就縮短了系統啟動(dòng)時(shí)間。
開(kāi)發(fā)人員需要了解 systemd 的更多細節。比如您打算開(kāi)發(fā)一個(gè)新的系統服務(wù),就必須了解如何讓這個(gè)服務(wù)能夠被 systemd 管理。這需要您注意以下這些要點(diǎn):
對于開(kāi)發(fā)者來(lái)說(shuō),工作量最大的部分應該是編寫(xiě)配置單元文件,定義所需要的單元。
舉例來(lái)說(shuō),開(kāi)發(fā)人員開(kāi)發(fā)了一個(gè)新的服務(wù)程序,比如 httpd,就需要為其編寫(xiě)一個(gè)配置單元文件以便該服務(wù)可以被 systemd 管理,類(lèi)似 UpStart 的工作配置文件。在該文件中定義服務(wù)啟動(dòng)的命令行語(yǔ)法,以及和其他服務(wù)的依賴(lài)關(guān)系等。
此外我們之前已經(jīng)了解到,systemd 的功能繁多,不僅用來(lái)管理服務(wù),還可以管理掛載點(diǎn),定義定時(shí)任務(wù)等。這些工作都是由編輯相應的配置單元文件完成的。我在這里給出幾個(gè)配置單元文件的例子。
下面是 SSH 服務(wù)的配置單元文件,服務(wù)配置單元文件以.service 為文件名后綴。
#cat /etc/system/system/sshd.service [Unit] Description=OpenSSH server daemon [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStartPre=/usr/sbin/sshd-keygen ExecStart=/usrsbin/sshd –D $OPTIONS ExecReload=/bin/kill –HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target
文件分為三個(gè)小節。第一個(gè)是[Unit]部分,這里僅僅有一個(gè)描述信息。第二部分是 Service 定義,其中,ExecStartPre 定義啟動(dòng)服務(wù)之前應該運行的命令;ExecStart 定義啟動(dòng)服務(wù)的具體命令行語(yǔ)法。第三部分是[Install],WangtedBy 表明這個(gè)服務(wù)是在多用戶(hù)模式下所需要的。
那我們就來(lái)看下 multi-user.target 吧:
#cat multi-user.target [Unit] Description=Multi-User System Documentation=man.systemd.special(7) Requires=basic.target Conflicts=rescue.service rescure.target After=basic.target rescue.service rescue.target AllowIsolate=yes [Install] Alias=default.target
第一部分中的 Requires 定義表明 multi-user.target 啟動(dòng)的時(shí)候 basic.target 也必須被啟動(dòng);另外 basic.target 停止的時(shí)候,multi-user.target 也必須停止。如果您接著(zhù)查看 basic.target 文件,會(huì )發(fā)現它又指定了 sysinit.target 等其他的單元必須隨之啟動(dòng)。同樣 sysinit.target 也會(huì )包含其他的單元。采用這樣的層層鏈接的結構,最終所有需要支持多用戶(hù)模式的組件服務(wù)都會(huì )被初始化啟動(dòng)好。
在[Install]小節中有 Alias 定義,即定義本單元的別名,這樣在運行 systemctl 的時(shí)候就可以使用這個(gè)別名來(lái)引用本單元。這里的別名是 default.target,比 multi-user.target 要簡(jiǎn)單一些。。。
此外在/etc/systemd/system 目錄下還可以看到諸如*.wants 的目錄,放在該目錄下的配置單元文件等同于在[Unit]小節中的 wants 關(guān)鍵字,即本單元啟動(dòng)時(shí),還需要啟動(dòng)這些單元。比如您可以簡(jiǎn)單地把您自己寫(xiě)的 foo.service 文件放入 multi-user.target.wants 目錄下,這樣每次都會(huì )被默認啟動(dòng)了。
最后,讓我們來(lái)看看 sys-kernel-debug.mout 文件,這個(gè)文件定義了一個(gè)文件掛載點(diǎn):
#cat sys-kernel-debug.mount[Unit]Description=Debug File SysteDefaultDependencies=noConditionPathExists=/sys/kernel/debugBefore=sysinit.target[Mount]What=debugfsWhere=/sys/kernel/debugType=debugfs
這個(gè)配置單元文件定義了一個(gè)掛載點(diǎn)。掛載配置單元文件有一個(gè)[Mount]配置小節,里面配置了 What,Where 和 Type 三個(gè)數據項。這都是掛載命令所必須的,例子中的配置等同于下面這個(gè)掛載命令:
mount –t debugfs /sys/kernel/debug debugfs
配置單元文件的編寫(xiě)需要很多的學(xué)習,必須參考 systemd 附帶的 man 等文檔進(jìn)行深入學(xué)習。希望通過(guò)上面幾個(gè)小例子,大家已經(jīng)了解配置單元文件的作用和一般寫(xiě)法了。
多數管理員應該都已經(jīng)非常熟悉系統服務(wù)和 init 系統的管理,比如 service、chkconfig 以及 telinit 命令的使用。systemd 也完成同樣的管理任務(wù),只是命令工具 systemctl 的語(yǔ)法有所不同而已,因此用表格來(lái)對比 systemctl 和傳統的系統管理命令會(huì )非常清晰。
| Sysvinit 命令 | Systemd 命令 | 備注 |
|---|---|---|
| service foo start | systemctl start foo.service | 用來(lái)啟動(dòng)一個(gè)服務(wù) (并不會(huì )重啟現有的) |
| service foo stop | systemctl stop foo.service | 用來(lái)停止一個(gè)服務(wù) (并不會(huì )重啟現有的)。 |
| service foo restart | systemctl restart foo.service | 用來(lái)停止并啟動(dòng)一個(gè)服務(wù)。 |
| service foo reload | systemctl reload foo.service | 當支持時(shí),重新裝載配置文件而不中斷等待操作。 |
| service foo condrestart | systemctl condrestart foo.service | 如果服務(wù)正在運行那么重啟它。 |
| service foo status | systemctl status foo.service | 匯報服務(wù)是否正在運行。 |
| ls /etc/rc.d/init.d/ | systemctl list-unit-files --type=service | 用來(lái)列出可以啟動(dòng)或停止的服務(wù)列表。 |
| chkconfig foo on | systemctl enable foo.service | 在下次啟動(dòng)時(shí)或滿(mǎn)足其他觸發(fā)條件時(shí)設置服務(wù)為啟用 |
| chkconfig foo off | systemctl disable foo.service | 在下次啟動(dòng)時(shí)或滿(mǎn)足其他觸發(fā)條件時(shí)設置服務(wù)為禁用 |
| chkconfig foo | systemctl is-enabled foo.service | 用來(lái)檢查一個(gè)服務(wù)在當前環(huán)境下被配置為啟用還是禁用。 |
| chkconfig –list | systemctl list-unit-files --type=service | 輸出在各個(gè)運行級別下服務(wù)的啟用和禁用情況 |
| chkconfig foo –list | ls /etc/systemd/system/*.wants/foo.service | 用來(lái)列出該服務(wù)在哪些運行級別下啟用和禁用。 |
| chkconfig foo –add | systemctl daemon-reload | 當您創(chuàng )建新服務(wù)文件或者變更設置時(shí)使用。 |
| telinit 3 | systemctl isolate multi-user.target (OR systemctl isolate runlevel3.target OR telinit 3) | 改變至多用戶(hù)運行級別。 |
除了表 2 列出的常見(jiàn)用法,系統管理員還需要了解其他一些系統配置和管理任務(wù)的改變。
首先我們了解 systemd 如何處理電源管理,命令如下表所示:
| 命令 | 操作 |
|---|---|
| systemctl reboot | 重啟機器 |
| systemctl poweroff | 關(guān)機 |
| systemctl suspend | 待機 |
| systemctl hibernate | 休眠 |
| systemctl hybrid-sleep | 混合休眠模式(同時(shí)休眠到硬盤(pán)并待機) |
關(guān)機不是每個(gè)登錄用戶(hù)在任何情況下都可以執行的,一般只有管理員才可以關(guān)機。正常情況下系統不應該允許 SSH 遠程登錄的用戶(hù)執行關(guān)機命令。否則其他用戶(hù)正在工作,一個(gè)用戶(hù)把系統關(guān)了就不好了。為了解決這個(gè)問(wèn)題,傳統的 Linux 系統使用 ConsoleKit 跟蹤用戶(hù)登錄情況,并決定是否賦予其關(guān)機的權限?,F在 ConsoleKit 已經(jīng)被 systemd 的 logind 所替代。
logind 不是 pid-1 的 init 進(jìn)程。它的作用和 UpStart 的 session init 類(lèi)似,但功能要豐富很多,它能夠管理幾乎所有用戶(hù)會(huì )話(huà)(session)相關(guān)的事情。logind 不僅是 ConsoleKit 的替代,它可以:
在不才作者看來(lái),作為系統初始化系統,systemd 的最大特點(diǎn)有兩個(gè):
此外,和其前任不同的地方在于,systemd 已經(jīng)不僅僅是一個(gè)初始化系統了。
Systemd 出色地替代了 sysvinit 的所有功能,但它并未就此自滿(mǎn)。因為 init 進(jìn)程是系統所有進(jìn)程的父進(jìn)程這樣的特殊性,systemd 非常適合提供曾經(jīng)由其他服務(wù)提供的功能,比如定時(shí)任務(wù) (以前由 crond 完成) ;會(huì )話(huà)管理 (以前由 ConsoleKit/PolKit 等管理) 。僅僅從本文皮毛一樣的介紹來(lái)看,Systemd 已經(jīng)管得很多了,可它還在不斷發(fā)展。它將逐漸成為一個(gè)多功能的系統環(huán)境,能夠處理非常多的系統管理任務(wù),有人甚至將它看作一個(gè)操作系統。
好的一點(diǎn)是,這非常有助于標準化 Linux 的管理!從前,不同的 Linux 發(fā)行版各行其事,使用不同方法管理系統,從來(lái)也不會(huì )互相妥協(xié)。比如如何將系統進(jìn)入休眠狀態(tài),不同的系統有不同的解決方案,即便是同一個(gè) Linux 系統,也存在不同的方法,比如一個(gè)有趣的討論:如何讓 ubuntu 系統休眠,可以使用底層的/sys/power/state 接口,也可以使用諸如 pm-utility 等高層接口。存在這么多種不同的方法做一件事情對像我這樣的普通用戶(hù)而言可不是件有趣的事情。systemd 提供統一的電源管理命令接口,這件事情的意義就類(lèi)似全世界的人都說(shuō)統一的語(yǔ)言,我們再也不需要學(xué)習外語(yǔ)了,多么美好!
如果所有的 Linux 發(fā)行版都采納了 systemd,那么系統管理任務(wù)便可以很大程度上實(shí)現標準化。此外 systemd 有個(gè)很棒的承諾:接口保持穩定,不會(huì )再輕易改動(dòng)。對于軟件開(kāi)發(fā)人員來(lái)說(shuō),這是多么體貼又讓人感動(dòng)的承諾??!
聯(lián)系客服