Systemd 是 Linux 系統中最新的初始化系統(init),它主要的設計目標是克服 sysvinit 固有的缺點,提升系統的啓動速度。systemd 和 ubuntu 的 upstart 是競爭對手,預計會取代 UpStart,實際上在做者寫做本文時,已經有消息稱 Ubuntu 也將採用 systemd 做爲其標準的系統初始化系統。html
Systemd 的不少概念來源於蘋果 Mac OS 操做系統上的 launchd,不過 launchd 專用於蘋果系統,所以長期未能得到應有的普遍關注。Systemd 借鑑了不少 launchd 的思想,它的重要特性以下:mysql
Systemd 是一個"新來的",Linux 上的不少應用程序並無來得及爲它作相應的改變。和 UpStart 同樣,systemd 引入了新的配置方式,對應用程序的開發也有一些新的要求。若是 systemd 想替代目前正在運行的初始化系統,就必須和現有程序兼容。任何一個 Linux 發行版都很難爲了採用 systemd 而在短期內將全部的服務代碼都修改一遍。linux
Systemd 提供了和 Sysvinit 以及 LSB initscripts 兼容的特性。系統中已經存在的服務和進程無需修改。這下降了系統向 systemd 遷移的成本,使得 systemd 替換現有初始化系統成爲可能。sql
Systemd 提供了比 UpStart 更激進的並行啓動能力,採用了 socket / D-Bus activation 等技術啓動服務。一個顯而易見的結果就是:更快的啓動速度。數據庫
爲了減小系統啓動時間,systemd 的目標是:ubuntu
儘量啓動更少的進程緩存
儘量將更多進程並行啓動安全
一樣地,UpStart 也試圖實現這兩個目標。UpStart 採用事件驅動機制,服務能夠暫不啓動,當須要的時候才經過事件觸發其啓動,這符合第一個設計目標;此外,不相干的服務能夠並行啓動,這也實現了第二個目標。服務器
下面的圖形演示了 UpStart 相對於 SysVInit 在併發啓動這個方面的改進:網絡
假設有 7 個不一樣的啓動項目, 好比 JobA、Job B 等等。在 SysVInit 中,每個啓動項目都由一個獨立的腳本負責,它們由 sysVinit 順序地,串行地調用。所以總的啓動時間爲 T1+T2+T3+T4+T5+T6+T7。其中一些任務有依賴關係,好比 A,B,C,D。
而 Job E 和 F 卻和 A,B,C,D 無關。這種狀況下,UpStart 可以併發地運行任務{E,F,(A,B,C,D)},使得總的啓動時間減小爲 T1+T2+T3。
這無疑增長了系統啓動的並行性,從而提升了系統啓動速度。可是在 UpStart 中,有依賴關係的服務仍是必須前後啓動。好比任務 A,B,(C,D)由於存在依賴關係,因此在這個局部,仍是串行執行。
讓 咱們例舉一些例子, Avahi 服務須要 D-Bus 提供的功能,所以 Avahi 的啓動依賴於 D-Bus,UpStart 中,Avahi 必須等到 D-Bus 啓動就緒以後纔開始啓動。相似的,livirtd 和 X11 都須要 HAL 服務先啓動,而全部這些服務都須要 syslog 服務記錄日誌,所以它們都必須等待 syslog 服務先啓動起來。然而 httpd 和他們都沒有關係,所以 httpd 能夠和 Avahi 等服務併發啓動。
Systemd 可以更進一步提升併發性,即使對於那些 UpStart 認爲存在相互依賴而必須串行的服務,好比 Avahi 和 D-Bus 也能夠併發啓動。從而實現以下圖所示的併發啓動過程:
全部的任務都同時併發執行,總的啓動時間被進一步下降爲 T1。
可見 systemd 比 UpStart 更進一步提升了並行啓動能力,極大地加速了系統啓動時間。
當 sysvinit 系統初始化的時候,它會將全部可能用到的後臺服務進程所有啓動運行。而且系統必須等待全部的服務都啓動就緒以後,才容許用戶登陸。這種作法有兩個缺點:首先是啓動時間過長;其次是系統資源浪費。
某 些服務極可能在很長一段時間內,甚至整個服務器運行期間都沒有被使用過。好比 CUPS,打印服務在多數服務器上不多被真正使用到。您可能沒有想到,在不少服務器上 SSHD 也是不多被真正訪問到的。花費在啓動這些服務上的時間是沒必要要的;一樣,花費在這些服務上的系統資源也是一種浪費。
Systemd 能夠提供按需啓動的能力,只有在某個服務被真正請求的時候才啓動它。當該服務結束,systemd 能夠關閉它,等待下次須要時再次啓動它。
init 系統的一個重要職責就是負責跟蹤和管理服務進程的生命週期。它不只能夠啓動一個服務,也必須也可以中止服務。這看上去沒有什麼特別的,然而在真正用代碼實現的時候,您或許會發現中止服務比一開始想的要困難。
服 務進程通常都會做爲精靈進程(daemon)在後臺運行,爲此服務程序有時候會派生(fork)兩次。在 UpStart 中,須要在配置文件中正確地配置 expect 小節。這樣 UpStart 經過對 fork 系統調用進行計數,從而獲知真正的精靈進程的 PID 號。好比圖 3 所示的例子:
若是 UpStart 找錯了,將 p1`做爲服務進程的 Pid,那麼中止服務的時候,UpStart 會試圖殺死 p1`進程,而真正的 p1``進程則繼續執行。換句話說該服務就失去控制了。
還有更加特殊的狀況。好比,一個 CGI 程序會派生兩次,從而脫離了和 Apache 的父子關係。當 Apache 進程被中止後,該 CGI 程序還在繼續運行。而咱們但願服務中止後,全部由它所啓動的相關進程也被中止。
爲 了處理這類問題,UpStart 經過 strace 來跟蹤 fork、exit 等系統調用,可是這種方法很笨拙,且缺少可擴展性。systemd 則利用了 Linux 內核的特性即 CGroup 來完成跟蹤的任務。當中止服務時,經過查詢 CGroup,systemd 能夠確保找到全部的相關進程,從而乾淨地中止服務。
CGroup 已經出現了好久,它主要用來實現系統資源配額管理。CGroup 提供了相似文件系統的接口,使用方便。當進程建立子進程時,子進程會繼承父進程的 CGroup。所以不管服務如何啓動新的子進程,全部的這些相關進程都會屬於同一個 CGroup,systemd 只須要簡單地遍歷指定的 CGroup 便可正確地找到全部的相關進程,將它們一一中止便可。
傳 統的 Linux 系統中,用戶能夠用/etc/fstab 文件來維護固定的文件系統掛載點。這些掛載點在系統啓動過程當中被自動掛載,一旦啓動過程結束,這些掛載點就會確保存在。這些掛載點都是對系統運行相當重要 的文件系統,好比 HOME 目錄。和 sysvinit 同樣,Systemd 管理這些掛載點,以便可以在系統啓動時自動掛載它們。Systemd 還兼容/etc/fstab 文件,您能夠繼續使用該文件管理掛載點。
有時候用戶還須要動態掛載點,好比打算訪問 DVD 內容時,才臨時執行掛載以便訪問其中的內容,而不訪問光盤時該掛載點被取消(umount),以便節約資源。傳統地,人們依賴 autofs 服務來實現這種功能。
Systemd 內建了自動掛載服務,無需另外安裝 autofs 服務,能夠直接使用 systemd 提供的自動掛載管理能力來實現 autofs 的功能。
系 統啓動過程是由不少的獨立工做共同組成的,這些工做之間可能存在依賴關係,好比掛載一個 NFS 文件系統必須依賴網絡可以正常工做。Systemd 雖然可以最大限度地併發執行不少有依賴關係的工做,可是相似"掛載 NFS"和"啓動網絡"這樣的工做仍是存在天生的前後依賴關係,沒法併發執行。對於這些任務,systemd 維護一個"事務一致性"的概念,保證全部相關的服務均可以正常啓動而不會出現互相依賴,以致於死鎖的狀況。
systemd 支持按需啓動,所以系統的運行狀態是動態變化的,人們沒法準確地知道系統當前運行了哪些服務。Systemd 快照提供了一種將當前系統運行狀態保存並恢復的能力。
比 如系統當前正運行服務 A 和 B,能夠用 systemd 命令行對當前系統運行情況建立快照。而後將進程 A 中止,或者作其餘的任意的對系統的改變,好比啓動新的進程 C。在這些改變以後,運行 systemd 的快照恢復命令,就可當即將系統恢復到快照時刻的狀態,即只有服務 A,B 在運行。一個可能的應用場景是調試:好比服務器出現一些異常,爲了調試用戶將當前狀態保存爲快照,而後能夠進行任意的操做,好比中止服務等等。等調試結 束,恢復快照便可。
這個快照功能目前在 systemd 中並不完善,彷佛開發人員也沒有特別關注它,所以有報告指出它還存在一些使用上的問題,使用時尚需慎重。
systemd 自帶日誌服務 journald,該日誌服務的設計初衷是克服現有的 syslog 服務的缺點。好比:
syslog 不安全,消息的內容沒法驗證。每個本地進程均可以聲稱本身是 Apache PID 4711,而 syslog 也就相信並保存到磁盤上。
數據沒有嚴格的格式,很是隨意。自動化的日誌分析器須要分析人類語言字符串來識別消息。一方面此類分析困難低效;此外日誌格式的變化會致使分析代碼須要更新甚至重寫。
Systemd Journal 用二進制格式保存全部日誌信息,用戶使用 journalctl 命令來查看日誌信息。無需本身編寫複雜脆弱的字符串分析處理程序。
Systemd Journal 的優勢以下:
簡單性:代碼少,依賴少,抽象開銷最小。
零維護:日誌是除錯和監控系統的核心功能,所以它本身不能再產生問題。舉例說,自動管理磁盤空間,避免因爲日誌的不斷產生而將磁盤空間耗盡。
移植性:日誌 文件應該在全部類型的 Linux 系統上可用,不管它使用的何種 CPU 或者字節序。
性能:添加和瀏覽 日誌 很是快。
最小資源佔用:日誌 數據文件須要較小。
統 一化:各類不一樣的日誌存儲技術應該統一塊兒來,將全部的可記錄事件保存在同一個數據存儲中。因此日誌內容的全局上下文都會被保存而且可供往後查詢。例如一條 固件記錄後一般會跟隨一條內核記錄,最終還會有一條用戶態記錄。重要的是當保存到硬盤上時這三者之間的關係不會丟失。Syslog 將不一樣的信息保存到不一樣的文件中,分析的時候很難肯定哪些條目是相關的。
擴展性:日誌的適用範圍很廣,從嵌入式設備到超級計算機集羣均可以知足需求。
安全性:日誌 文件是能夠驗證的,讓沒法檢測的修改再也不可能。
系 統初始化須要作的事情很是多。須要啓動後臺服務,好比啓動 SSHD 服務;須要作配置工做,好比掛載文件系統。這個過程當中的每一步都被 systemd 抽象爲一個配置單元,即 unit。能夠認爲一個服務是一個配置單元;一個掛載點是一個配置單元;一個交換分區的配置是一個配置單元;等等。systemd 將配置單元概括爲如下一些不一樣的類型。然而,systemd 正在快速發展,新功能不斷增長。因此配置單元類型可能在不久的未來繼續增長。
service :表明一個後臺服務進程,好比 mysqld。這是最經常使用的一類。
socket :此類配置單元封裝系統和互聯網中的一個 套接字 。當下,systemd 支持流式、數據報和連續包的 AF_INET、AF_INET六、AF_UNIX socket 。每個套接字配置單元都有一個相應的服務配置單元 。相應的服務在第一個"鏈接"進入套接字時就會啓動(例如:nscd.socket 在有新鏈接後便啓動 nscd.service)。
device :此類配置單元封裝一個存在於 Linux 設備樹中的設備。每個使用 udev 規則標記的設備都將會在 systemd 中做爲一個設備配置單元出現。
mount :此類配置單元封裝文件系統結構層次中的一個掛載點。Systemd 將對這個掛載點進行監控和管理。好比能夠在啓動時自動將其掛載;能夠在某些條件下自動卸載。Systemd 會將/etc/fstab 中的條目都轉換爲掛載點,並在開機時處理。
automount :此類配置單元封裝系統結構層次中的一個自掛載點。每個自掛載配置單元對應一個掛載配置單元 ,當該自動掛載點被訪問時,systemd 執行掛載點中定義的掛載行爲。
swap: 和掛載配置單元相似,交換配置單元用來管理交換分區。用戶能夠用交換配置單元來定義系統中的交換分區,可讓這些交換分區在啓動時被激活。
target :此類配置單元爲其餘配置單元進行邏輯分組。它們自己實際上並不作什麼,只是引用其餘配置單元而已。這樣即可以對配置單元作一個統一的控制。這樣就能夠實 現你們都已經很是熟悉的運行級別概念。好比想讓系統進入圖形化模式,須要運行許多服務和配置命令,這些操做都由一個個的配置單元表示,將全部這些配置單元 組合爲一個目標(target),就表示須要將這些配置單元所有執行一遍以便進入目標所表明的系統運行狀態。 (例如:multi-user.target 至關於在傳統使用 SysV 的系統中運行級別 5)
timer:定時器配置單元用來定時觸發用戶定義的操做,這類配置單元取代了 atd、crond 等傳統的定時服務。
snapshot :與 target 配置單元類似,快照是一組配置單元。它保存了系統當前的運行狀態。
每一個配置單元都有一個對應的配置文件,系統管理員的任務就是編寫和維護這些不一樣的配置文件,好比一個 MySQL 服務對應一個 mysql.service 文件。這種配置文件的語法很是簡單,用戶不須要再編寫和維護複雜的系統 5 腳本了。
雖 然 systemd 將大量的啓動工做解除了依賴,使得它們能夠併發啓動。但仍是存在有些任務,它們之間存在天生的依賴,不能用"套接字激活"(socket activation)、D-Bus activation 和 autofs 三大方法來解除依賴(三大方法詳情見後續描述)。好比:掛載必須等待掛載點在文件系統中被建立;掛載也必須等待相應的物理設備就緒。爲了解決這類依賴問 題,systemd 的配置單元之間能夠彼此定義依賴關係。
Systemd 用配置單元定義文件中的關鍵字來描述配置單元之間的依賴關係。好比:unit A 依賴 unit B,能夠在 unit B 的定義中用"require A"來表示。這樣 systemd 就會保證先啓動 A 再啓動 B。
Systemd 能保證事務完整性。Systemd 的事務概念和數據庫中的有所不一樣,主要是爲了保證多個依賴的配置單元之間沒有環形引用。好比 unit A、B、C,假如它們的依賴關係爲:
存 在循環依賴,那麼 systemd 將沒法啓動任意一個服務。此時 systemd 將會嘗試解決這個問題,由於配置單元之間的依賴關係有兩種:required 是強依賴;want 則是弱依賴,systemd 將去掉 wants 關鍵字指定的依賴看看是否能打破循環。若是沒法修復,systemd 會報錯。
Systemd 可以自動檢測和修復這類配置錯誤,極大地減輕了管理員的排錯負擔。
systemd 用目標(target)替代了運行級別的概念,提供了更大的靈活性,如您能夠繼承一個已有的目標,並添加其它服務,來建立本身的目標。下表列舉了 systemd 下的目標和常見 runlevel 的對應關係:
Sysvinit 運行級別 | Systemd 目標 | 備註 |
---|---|---|
0 | runlevel0.target, poweroff.target | 關閉系統。 |
1, s, single | runlevel1.target, rescue.target | 單用戶模式。 |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用戶定義/域特定運行級別。默認等同於 3。 |
3 | runlevel3.target, multi-user.target | 多用戶,非圖形化。用戶能夠經過多個控制檯或網絡登陸。 |
5 | runlevel5.target, graphical.target | 多用戶,圖形化。一般爲全部運行級別 3 的服務外加圖形化登陸。 |
6 | runlevel6.target, reboot.target | 重啓 |
emergency | emergency.target | 緊急 Shell |
如 前所述,在 Systemd 中,全部的服務都併發啓動,好比 Avahi、D-Bus、livirtd、X十一、HAL 能夠同時啓動。乍一看,這彷佛有點兒問題,好比 Avahi 須要 syslog 的服務,Avahi 和 syslog 同時啓動,假設 Avahi 的啓動比較快,因此 syslog 尚未準備好,但是 Avahi 又須要記錄日誌,這豈不是會出現問題?
Systemd 的開發人員仔細研究了服務之間相互依賴的本質問題,發現所謂依賴能夠分爲三個具體的類型,而每個類型實際上均可以經過相應的技術解除依賴關係。
絕 大多數的服務依賴是套接字依賴。好比服務 A 經過一個套接字端口 S1 提供本身的服務,其餘的服務若是須要服務 A,則須要鏈接 S1。所以若是服務 A 還沒有啓動,S1 就不存在,其餘的服務就會獲得啓動錯誤。因此傳統地,人們須要先啓動服務 A,等待它進入就緒狀態,再啓動其餘須要它的服務。Systemd 認爲,只要咱們預先把 S1 創建好,那麼其餘全部的服務就能夠同時啓動而無需等待服務 A 來建立 S1 了。若是服務 A 還沒有啓動,那麼其餘進程向 S1 發送的服務請求實際上會被 Linux 操做系統緩存,其餘進程會在這個請求的地方等待。一旦服務 A 啓動就緒,就能夠當即處理緩存的請求,一切都開始正常運行。
那麼服務如何使用由 init 進程建立的套接字呢?
Linux 操做系統有一個特性,當進程調用 fork 或者 exec 建立子進程以後,全部在父進程中被打開的文件句柄 (file descriptor) 都被子進程所繼承。套接字也是一種文件句柄,進程 A 能夠建立一個套接字,此後當進程 A 調用 exec 啓動一個新的子進程時,只要確保該套接字的 close_on_exec 標誌位被清空,那麼新的子進程就能夠繼承這個套接字。子進程看到的套接字和父進程建立的套接字是同一個系統套接字,就彷彿這個套接字是子進程本身建立的一 樣,沒有任何區別。
這個特性之前被一個叫作 inetd 的系統服務所利用。Inetd 進程會負責監控一些經常使用套接字端口,好比 Telnet,當該端口有鏈接請求時,inetd 才啓動 telnetd 進程,並把有鏈接的套接字傳遞給新的 telnetd 進程進行處理。這樣,當系統沒有 telnet 客戶端鏈接時,就不須要啓動 telnetd 進程。Inetd 能夠代理不少的網絡服務,這樣就能夠節約不少的系統負載和內存資源,只有當有真正的鏈接請求時才啓動相應服務,並把套接字傳遞給相應的服務進程。
和 inetd 相似,systemd 是全部其餘進程的父進程,它能夠先創建全部須要的套接字,而後在調用 exec 的時候將該套接字傳遞給新的服務進程,而新進程直接使用該套接字進行服務便可。
D-Bus 是 desktop-bus 的簡稱,是一個低延遲、低開銷、高可用性的進程間通訊機制。它愈來愈多地用於應用程序之間通訊,也用於應用程序和操做系統內核之間的通訊。不少現代的服務 進程都使用D-Bus 取代套接字做爲進程間通訊機制,對外提供服務。好比簡化 Linux 網絡配置的 NetworkManager 服務就使用 D-Bus 和其餘的應用程序或者服務進行交互:郵件客戶端軟件 evolution 能夠經過 D-Bus 從 NetworkManager 服務獲取網絡狀態的改變,以便作出相應的處理。
D-Bus 支持所謂"bus activation"功能。若是服務 A 須要使用服務 B 的 D-Bus 服務,而服務 B 並無運行,則 D-Bus 能夠在服務 A 請求服務 B 的 D-Bus 時自動啓動服務 B。而服務 A 發出的請求會被 D-Bus 緩存,服務 A 會等待服務 B 啓動就緒。利用這個特性,依賴 D-Bus 的服務就能夠實現並行啓動。
系 統啓動過程當中,文件系統相關的活動是最耗時的,好比掛載文件系統,對文件系統進行磁盤檢查(fsck),磁盤配額檢查等都是很是耗時的操做。在等待這些工 做完成的同時,系統處於空閒狀態。那些想使用文件系統的服務彷佛必須等待文件系統初始化完成才能夠啓動。可是 systemd 發現這種依賴也是能夠避免的。
Systemd 參考了 autofs 的設計思路,使得依賴文件系統的服務和文件系統自己初始化二者能夠併發工做。autofs 能夠監測到某個文件系統掛載點真正被訪問到的時候才觸發掛載操做,這是經過內核 automounter 模塊的支持而實現的。好比一個 open()系統調用做用在"/misc/cd/file1"的時候,/misc/cd 還沒有執行掛載操做,此時 open()調用被掛起等待,Linux 內核通知 autofs,autofs 執行掛載。這時候,控制權返回給 open()系統調用,並正常打開文件。
Systemd 集成了 autofs 的實現,對於系統中的掛載點,好比/home,當系統啓動的時候,systemd 爲其建立一個臨時的自動掛載點。在這個時刻/home 真正的掛載設備還沒有啓動好,真正的掛載操做尚未執行,文件系統檢測也尚未完成。但是那些依賴該目錄的進程已經能夠併發啓動,他們的 open()操做被內建在 systemd 中的 autofs 捕獲,將該 open()調用掛起(可中斷睡眠狀態)。而後等待真正的掛載操做完成,文件系統檢測也完成後,systemd 將該自動掛載點替換爲真正的掛載點,並讓 open()調用返回。由此,實現了那些依賴於文件系統的服務和文件系統自己同時併發啓動。
固然對於"/"根目錄的依賴實際上必定仍是要串行執行,由於 systemd 本身也存放在/之下,必須等待系統根目錄掛載檢查好。
不 過對於相似/home 等掛載點,這種併發能夠提升系統的啓動速度,尤爲是當/home 是遠程的 NFS 節點,或者是加密盤等,須要耗費較長的時間才能夠準備就緒的狀況下,由於併發啓動,這段時間內,系統並非徹底無事可作,而是能夠利用這段空餘時間作更多 的啓動進程的事情,總的來講就縮短了系統啓動時間。
下 面針對技術人員的不一樣角色來簡單地介紹一下 systemd 的使用。本文只打算給出簡單的描述,讓您對 systemd 的使用有一個大概的理解。具體的細節內容太多,即沒法在一篇短文內寫全,本人也沒有那麼強大的能力。還須要讀者本身去進一步查閱 systemd 的文檔。
開發人員須要瞭解 systemd 的更多細節。好比您打算開發一個新的系統服務,就必須瞭解如何讓這個服務可以被 systemd 管理。這須要您注意如下這些要點:
後臺服務進程代碼不須要執行兩次派生來實現後臺精靈進程,只須要實現服務自己的主循環便可。
不要調用 setsid(),交給 systemd 處理
再也不須要維護 pid 文件。
Systemd 提供了日誌功能,服務進程只須要輸出到 stderr 便可,無需使用 syslog。
處理信號 SIGTERM,這個信號的惟一正確做用就是中止當前服務,不要作其餘的事情。
SIGHUP 信號的做用是重啓服務。
須要套接字的服務,不要本身建立套接字,讓 systemd 傳入套接字。
使用 sd_notify()函數通知 systemd 服務本身的狀態改變。通常地,當服務初始化結束,進入服務就緒狀態時,能夠調用它。
Unit 文件的編寫
對於開發者來講,工做量最大的部分應該是編寫配置單元文件,定義所須要的單元。
舉例來講,開發人員開發了一個新的服務程序,好比 httpd,就須要爲其編寫一個配置單元文件以便該服務能夠被 systemd 管理,相似 UpStart 的工做配置文件。在該文件中定義服務啓動的命令行語法,以及和其餘服務的依賴關係等。
此外咱們以前已經瞭解到,systemd 的功能繁多,不只用來管理服務,還能夠管理掛載點,定義定時任務等。這些工做都是由編輯相應的配置單元文件完成的。我在這裏給出幾個配置單元文件的例子。
下面是 SSH 服務的配置單元文件,服務配置單元文件以.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
文件分爲三個小節。第一個是[Unit]部分,這裏僅僅有一個 描述信息。第二部分是 Service 定義,其中,ExecStartPre 定義啓動服務以前應該運行的命令;ExecStart 定義啓動服務的具體命令行語法。第三部分是[Install],WangtedBy 代表這個服務是在多用戶模式下所須要的。
那咱們就來看下 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 啓動的時候 basic.target 也必須被啓動;另外 basic.target 中止的時候,multi-user.target 也必須中止。若是您接着查看 basic.target 文件,會發現它又指定了 sysinit.target 等其餘的單元必須隨之啓動。一樣 sysinit.target 也會包含其餘的單元。採用這樣的層層連接的結構,最終全部須要支持多用戶模式的組件服務都會被初始化啓動好。
在[Install]小節中有 Alias 定義,即定義本單元的別名,這樣在運行 systemctl 的時候就可使用這個別名來引用本單元。這裏的別名是 default.target,比 multi-user.target 要簡單一些。。。
此 外在/etc/systemd/system 目錄下還能夠看到諸如*.wants 的目錄,放在該目錄下的配置單元文件等同於在[Unit]小節中的 wants 關鍵字,即本單元啓動時,還須要啓動這些單元。好比您能夠簡單地把您本身寫的 foo.service 文件放入 multi-user.target.wants 目錄下,這樣每次都會被默認啓動了。
最後,讓咱們來看看 sys-kernel-debug.mout 文件,這個文件定義了一個文件掛載點:
#cat sys-kernel-debug.mount [Unit] Description=Debug File Syste DefaultDependencies=no ConditionPathExists=/sys/kernel/debug Before=sysinit.target [Mount] What=debugfs Where=/sys/kernel/debug Type=debugfs
這個配置單元文件定義了一個掛載點。掛載配置單元文件有一個[Mount]配置小節,裏面配置了 What,Where 和 Type 三個數據項。這都是掛載命令所必須的,例子中的配置等同於下面這個掛載命令:
mount –t debugfs /sys/kernel/debug debugfs
配置單元文件的編寫須要不少的學習,必須參考 systemd 附帶的 man 等文檔進行深刻學習。但願經過上面幾個小例子,你們已經瞭解配置單元文件的做用和通常寫法了。
systemd 的主要命令行工具是 systemctl。
多 數管理員應該都已經很是熟悉系統服務和 init 系統的管理,好比 service、chkconfig 以及 telinit 命令的使用。systemd 也完成一樣的管理任務,只是命令工具 systemctl 的語法有所不一樣而已,所以用表格來對比 systemctl 和傳統的系統管理命令會很是清晰。
Sysvinit 命令 | Systemd 命令 | 備註 |
---|---|---|
service foo start | systemctl start foo.service | 用來啓動一個服務 (並不會重啓現有的) |
service foo stop | systemctl stop foo.service | 用來中止一個服務 (並不會重啓現有的)。 |
service foo restart | systemctl restart foo.service | 用來中止並啓動一個服務。 |
service foo reload | systemctl reload foo.service | 當支持時,從新裝載配置文件而不中斷等待操做。 |
service foo condrestart | systemctl condrestart foo.service | 若是服務正在運行那麼重啓它。 |
service foo status | systemctl status foo.service | 彙報服務是否正在運行。 |
ls /etc/rc.d/init.d/ | systemctl list-unit-files --type=service | 用來列出能夠啓動或中止的服務列表。 |
chkconfig foo on | systemctl enable foo.service | 在下次啓動時或知足其餘觸發條件時設置服務爲啓用 |
chkconfig foo off | systemctl disable foo.service | 在下次啓動時或知足其餘觸發條件時設置服務爲禁用 |
chkconfig foo | systemctl is-enabled foo.service | 用來檢查一個服務在當前環境下被配置爲啓用仍是禁用。 |
chkconfig –list | systemctl list-unit-files --type=service | 輸出在各個運行級別下服務的啓用和禁用狀況 |
chkconfig foo –list | ls /etc/systemd/system/*.wants/foo.service | 用來列出該服務在哪些運行級別下啓用和禁用。 |
chkconfig foo –add | systemctl daemon-reload | 當您建立新服務文件或者變動設置時使用。 |
telinit 3 | systemctl isolate multi-user.target (OR systemctl isolate runlevel3.target OR telinit 3) | 改變至多用戶運行級別。 |
除了表 2 列出的常見用法,系統管理員還須要瞭解其餘一些系統配置和管理任務的改變。
首先咱們瞭解 systemd 如何處理電源管理,命令以下表所示:
命令 | 操做 |
---|---|
systemctl reboot | 重啓機器 |
systemctl poweroff | 關機 |
systemctl suspend | 待機 |
systemctl hibernate | 休眠 |
systemctl hybrid-sleep | 混合休眠模式(同時休眠到硬盤並待機) |
關機不是每一個登陸用戶在任何狀況下均可以執行的,通常只有管理員才能夠關機。正常狀況下系統 不該該容許 SSH 遠程登陸的用戶執行關機命令。不然其餘用戶正在工做,一個用戶把系統關了就很差了。爲了解決這個問題,傳統的 Linux 系統使用 ConsoleKit 跟蹤用戶登陸狀況,並決定是否賦予其關機的權限。如今 ConsoleKit 已經被 systemd 的 logind 所替代。
logind 不是 pid-1 的 init 進程。它的做用和 UpStart 的 session init 相似,但功能要豐富不少,它可以管理幾乎全部用戶會話(session)相關的事情。logind 不只是 ConsoleKit 的替代,它能夠:
維 護,跟蹤會話和用戶登陸狀況。如上所述,爲了決定關機命令是否可行,系統須要瞭解當前用戶登陸狀況,若是用戶從 SSH 登陸,不容許其執行關機命令;若是普通用戶從本地登陸,且該用戶是系統中的惟一會話,則容許其執行關機命令;這些判斷都須要 logind 維護全部的用戶會話和登陸狀況。
Logind 也負責統計用戶會話是否長時間沒有操做,能夠執行休眠/關機等相應操做。
爲用戶會話的全部進程建立 CGroup。這不只方便統計全部用戶會話的相關進程,也能夠實現會話級別的系統資源控制。
負責電源管理的組合鍵處理,好比用戶按下電源鍵,將系統切換至睡眠狀態。
多 席位(multi-seat) 管理。現在的電腦,即使一臺筆記本電腦,也徹底能夠提供多人同時使用的計算能力。多席位就是一臺電腦主機管理多個外設,好比兩個屏幕和兩個鼠標/鍵盤。席 位一使用屏幕 1 和鍵盤 1;席位二使用屏幕 2 和鍵盤 2,但他們都共享一臺主機。用戶會話能夠自由在多個席位之間切換。或者當插入新的鍵盤,屏幕等物理外設時,自動啓動 gdm 用戶登陸界面等。全部這些都是多席位管理的內容。ConsoleKit 始終沒有實現這個功能,systemd 的 logind 可以支持多席位。
以上描述的這些管理功能僅僅是 systemd 的部分功能,除此以外,systemd 還負責系統其餘的管理配置,好比配置網絡,Locale 管理,管理系統內核模塊加載等,完整地描述它們已經超出了本人的能力。
在不才做者看來,做爲系統初始化系統,systemd 的最大特色有兩個:
使人驚奇的激進的併發啓動能力,極大地提升了系統啓動速度;
用 CGroup 統計跟蹤子進程,乾淨可靠。
此外,和其前任不一樣的地方在於,systemd 已經不只僅是一個初始化系統了。
Systemd 出色地替代了 sysvinit 的全部功能,但它並未就此自滿。由於 init 進程是系統全部進程的父進程這樣的特殊性,systemd 很是適合提供曾經由其餘服務提供的功能,好比定時任務 (之前由 crond 完成) ;會話管理 (之前由 ConsoleKit/PolKit 等管理) 。僅僅從本文皮毛同樣的介紹來看,Systemd 已經管得不少了,可它還在不斷髮展。它將逐漸成爲一個多功能的系統環境,可以處理很是多的系統管理任務,有人甚至將它看做一個操做系統。
好 的一點是,這很是有助於標準化 Linux 的管理!從前,不一樣的 Linux 發行版各行其事,使用不一樣方法管理系統,歷來也不會互相妥協。好比如何將系統進入休眠狀態,不一樣的系統有不一樣的解決方案,即使是同一個 Linux 系統,也存在不一樣的方法,好比一個有趣的討論:如何讓 ubuntu 系統休眠, 可使用底層的/sys/power/state 接口,也可使用諸如 pm-utility 等高層接口。存在這麼多種不一樣的方法作一件事情對像我這樣的普通用戶而言可不是件有趣的事情。systemd 提供統一的電源管理命令接口,這件事情的意義就相似全世界的人都說統一的語言,咱們不再須要學習外語了,多麼美好!
若是全部的 Linux 發行版都採納了 systemd,那麼系統管理任務即可以很大程度上實現標準化。此外 systemd 有個很棒的承諾:接口保持穩定,不會再輕易改動。對於軟件開發人員來講,這是多麼體貼又讓人感動的承諾啊!
本 系列文章從古老卻簡明穩定的 sysvinit 提及,接着簡要描述了 UpStart 帶來的清新改變,最後看到了充滿野心和活力的新生代 systemd 系統逐漸統治 Linux 的各個版本。就好像在看咱們這個世界,一代人老去,新的一代帶着橫掃一切的氣概登上舞臺,尚未喊出他們最有力的口號,更猛的一代已經把聚光燈和全部的目 光帶走。Systemd 以後也許還有更新的 init 系統出現吧,讓咱們繼續期待。。。