玖玖资源站亚洲av_日本乱偷中文字幕一二三区_久久这里只有精品98_亚洲特级黄片视频_男女很舒服爽视频免费_国产一二三四2021精字窝_国产高潮白浆一区_自拍日本高清三级_秘书高跟黑色丝袜国产在线_亚洲A v永久无码精品网站色欲

NEWS

新聞

了解優(yōu)麒麟最新資訊,關(guān)注社區(qū)和產(chǎn)品動態(tài)。

NEWS

Learn about the latest news.

干貨分享 - Systemd 技術(shù)原理&實踐(上)

2021-10-09 09:17:23

優(yōu)麒麟的程序員小哥在研究如何優(yōu)化系統(tǒng)資源模塊時,查閱了許許多多的資料,發(fā)現(xiàn)沒有一篇能詳細把 systemd 的優(yōu)勢與原理說得很清楚的中文介紹文章,于是自己動手下載了 systemd 的源碼,對照資料匯總了一份有關(guān) systemd 的詳解文章,希望能對研究 systemd 的優(yōu)客有所幫助。


systemd 介紹

 1. systemd 的起源

關(guān)于 systemd 的起源,首先要從 Linux 的 init 程序說起。Linux 系統(tǒng)在啟動過程中,內(nèi)核完成初始化以后,由內(nèi)核第一個啟動的程序便是 init 程序,路徑為 /sbin/init(為一個軟連接,鏈接到真實的 init 進程),其 PID 為1,它為系統(tǒng)里所有進程的“祖先”,Linux 中所有的進程都由 init 進程直接或間接進行創(chuàng)建并運行,init 進程以守護進程的方式存在,負責組織與運行系統(tǒng)的相關(guān)初始化工作,讓系統(tǒng)進入定義好的運行模式,如命令行模式或圖形界面模式。

init 程序的發(fā)展,大體上可分為三個階段:sysvinit->upstart->systemd,根據(jù) init 進程的發(fā)展特性,可以簡單理解為如下:

sysvinit:init 系統(tǒng)通過 shell 腳本以串行的方式啟動系統(tǒng)服務(wù),下一個進程必須等待上一個進程啟動完成后才能開始啟動,因此系統(tǒng)啟動的過程比較慢。

upstart:在 sysvinit 的基礎(chǔ)上,把一些沒有關(guān)聯(lián)的程序并行啟動,以提高啟動的速度,但是存在依賴關(guān)系的程序仍然為串行啟動。

systemd:通過套接字激活的機制,讓所有無論有無依賴關(guān)系的程序全部并行啟動,并且僅按照系統(tǒng)啟動的需要啟動相應(yīng)的服務(wù),最大化提高開機啟動速度。

目前優(yōu)麒麟操作系統(tǒng)使用的就為 systemd。systemd 的意思為 system daemon,意為系統(tǒng)守護進程,由 Lennart Poettering 帶頭開發(fā),采用更加優(yōu)秀的服務(wù)框架,并且與老的 sysvinit 兼容,其設(shè)計目的就是克服 sysvinit 與 upstart 的缺點,進一步地提高啟動速度。目前主流的系統(tǒng)中,systemd 的守護進程主要分為系統(tǒng)態(tài)(system)與用戶態(tài)(user),可以在 ps -ef 中看到 systemd 的守護進程,如下:

優(yōu)麒麟(Ubuntu Kylin)

PID 為1的進程/sbin/init 即是 system 態(tài)的 systemd,它為一個軟鏈接,指向真實的 systemd 路徑,在優(yōu)麒麟操作系統(tǒng)中一般放在/lib/systemd/目錄:

優(yōu)麒麟(Ubuntu Kylin)

systemd 為進程服務(wù)集合的總稱,它包含許多的進程,負責控制、管理系統(tǒng)的資源,其中包括 systemd-login,負責用戶登錄相關(guān)信息的創(chuàng)建、修改與刪除;systemd-sleep 控制系統(tǒng)的休眠、睡眠狀態(tài)切換等等。在優(yōu)麒麟操作系統(tǒng)下,它們主要集中在/lib/systemd/文件目錄:

優(yōu)麒麟(Ubuntu Kylin)

每個進程的主要用途可以閱讀 freedesktop systemd 手冊:https://www.freedesktop.org/software/systemd/man/ 

目前 systemd 占據(jù) init 程序的主導(dǎo),有統(tǒng)一天下的趨勢。

2. systemd 的主要功能

systemd 采用并行的啟動方式,并提供按需啟動的方式:systemd 在設(shè)計之初最關(guān)注兩件事情:更少的開始,更多的并行。更少的開始,意味著在開機啟動階段,systemd 僅啟動系統(tǒng)啟動時必要的一些服務(wù),更多其他的服務(wù)推遲啟動,直到真正需要它的時候,例如優(yōu)麒麟的藍牙 bluetooth 與截圖相關(guān)的服務(wù),開機的時候系統(tǒng)不會用到它;優(yōu)麒麟的 U 盤啟動器相關(guān)的服務(wù),可以等到接入 U 盤的時候再啟動;如果系統(tǒng)未連接到網(wǎng)絡(luò),那那些需要用到網(wǎng)絡(luò)的相關(guān)服務(wù)也可以無需啟動,直到網(wǎng)絡(luò)連通后的第一次連接再啟動即可。更多的并行,意味著服務(wù)的啟動不需要像 sysvinit 一樣序列化啟動,而是同時運行所有需要的服務(wù),以便系統(tǒng) cpu 資源利用的最大化,因此總的啟動時間最小化,后面會介紹 systemd 是如何實現(xiàn)所有服務(wù)并行啟動。

采用 cgroup 跟蹤管理進程的生命周期:cgroup 為控制組,是一個層級結(jié)構(gòu),類似與文件管理系統(tǒng)的結(jié)構(gòu)。當一個進程創(chuàng)建了子進程,子進程會繼承父進程的 cgroup,就好比子進程創(chuàng)建在父進程的目錄下,當子進程又創(chuàng)建一個子進程時,這個子進程會繼承上一個子進程的 cgroup,也就相當與繼承了父進程的 cgroup,好比這個子進程創(chuàng)建在上一個子進程的目錄下,也就在父進程的目錄下,通過這一機制就可以把父進程與所有的子進程關(guān)聯(lián)起來并進行跟蹤,當停止父進程時,可以通過查詢 cgroup 找到所有關(guān)聯(lián)的子進程,從而確保干凈的停止所有相關(guān)服務(wù)。

啟動掛載與自動掛載:在系統(tǒng)啟動過程中,systemd 在初始化時會自身進行一些掛載,如/sys 目錄與/run 目錄的掛載,這些都是系統(tǒng)啟動時至關(guān)重要的文件系統(tǒng)。systemd 還能實現(xiàn)動態(tài)掛載點的自動掛載,例如不需要經(jīng)常使用的光盤、U 盤的掛載,只在這些設(shè)備接入時,systemd 啟動相應(yīng)的服務(wù)并對其進行臨時的掛載以便訪問其中的內(nèi)容,當這些設(shè)備拔出時,這些掛載點將被取消以便節(jié)約資源。

事務(wù)的依賴關(guān)系管理:系統(tǒng)有很多的服務(wù)存在依賴關(guān)系,例如麒麟軟件商店需要等待網(wǎng)絡(luò)服務(wù)的啟動,lightdm 與 systemd 交互需要等待 D-Bus 的啟動,大多數(shù)服務(wù)也需要等待 syslog 的完全啟動與初始化。systemd 采用 Unit(配置單元)管理這些服務(wù)的依賴關(guān)系,維護一個事務(wù)的一致性,并保證所有的相關(guān)服務(wù)不會出現(xiàn)相互依賴而產(chǎn)生死鎖的情況,后面會對 Unit 進行詳細介紹。

日志:systemd 自帶 journalctl 命令來查看系統(tǒng)保存的所有日志信息,并且可以支持通過一些參數(shù)來對日志進行過濾,方便用戶進行日志分析。

其他:systemd 經(jīng)過幾代的更新,實現(xiàn)的功能已經(jīng)十分的多了,甚至有人覺得 systemd 管得太多了,導(dǎo)致一些服務(wù)都沒有了存在的必要。例如 systemd 添加了許多 systemctl 的命令,可以實現(xiàn)系統(tǒng)電源的管理;systemd 還添加了看門狗機制,其他守護進程需要定期 ping systemd 進程,否則會視為失敗而重啟它等等。詳情可以去閱讀設(shè)計師的博客 http://0pointer.de/blog/projects  。

3. systemd 如何實現(xiàn)服務(wù)的并行

systemd 的設(shè)計理念就是希望讓所有的服務(wù)并行的啟動,以最大化利用硬件資源,提高啟動的時間。但是我們知道服務(wù)之間存在依賴關(guān)系,客戶端需要等待服務(wù)端的啟動才可以建立連接,例如前面提到的,在優(yōu)麒麟操作系統(tǒng)中,所有的服務(wù)都需要等待 syslog 服務(wù)的啟動,那 systemd 是如何擺脫這同步和序列化過程的呢?

systemd 的設(shè)計師認為,對于傳統(tǒng)的守護進程,他們真正實際等待另一個守護進程提供的是套接字的準備,需要的是一個文件系統(tǒng)的 socket 套接字描述符,這是它們唯一等待的,因此是否可以設(shè)法讓這些套接字描述符可以更早的創(chuàng)建用于連接,從而不用等待整個守護進程完整的啟動?答案是可以的。

在 C 語言中,一個進程啟動另一個進程時,一般是執(zhí)行系統(tǒng)調(diào)用 exec(),systemd 在調(diào)用 exec()來啟動服務(wù)之前,先創(chuàng)建與該服務(wù)關(guān)聯(lián)的監(jiān)聽套接字并激活,然后在 exec()啟動服務(wù)期間把套接字傳遞給它,因此在服務(wù)還在啟動的時候,套接字就已經(jīng)處于可用的狀態(tài)。通過這一方式,systemd 可以在第一步中為所有的服務(wù)創(chuàng)建套接字,然后第二步一次運行所有的服務(wù),如果一個服務(wù)需要依賴于另一個服務(wù),由于套接字已經(jīng)準備好,服務(wù)之間可以直接進行連接并繼續(xù)執(zhí)行啟動,如果遇到了需要同步的請求,不得不等待阻塞的情況,那阻塞的也將只會是一個服務(wù),并且只是一個服務(wù)的一個請求,不會影響其他服務(wù)的啟動,由此實現(xiàn)服務(wù)之間不需要再進行序列化的啟動。Linux 內(nèi)核提供了套接字緩沖區(qū)功能,幫助 systemd 實現(xiàn)了最大的并行化,還是拿 syslog 服務(wù)來說,優(yōu)麒麟操作系統(tǒng)上大多數(shù)服務(wù)在啟動初期都會先進行日志相關(guān)的初始化配置,如果同時啟動 syslog 服務(wù)與各種 syslog 的客戶端服務(wù),由于 syslog 相關(guān)套接字在 systemd 執(zhí)行 exec()啟動 syslog 之前已經(jīng)創(chuàng)建并準備好,客戶端可以直接連接到 syslog 的套接字上,如果遇到 syslog 啟動比較慢,客戶端向 syslog 發(fā)送請求消息,syslog 還無法處理的情況,通過內(nèi)核 socket 緩沖區(qū)的機制,請求的消息將會傳到 syslog 套接字的緩沖區(qū)之中,只要緩沖區(qū)未滿,客戶端就不需要等待并繼續(xù)往下執(zhí)行;一旦 syslog 服務(wù)完全啟動,它就會使所有消息出列并處理他們;當出現(xiàn)另一種情況,緩沖區(qū)已滿,或者需要同步消息請求的情況,雖然這個時候客戶端不得不阻塞等待,但是也只有一個客戶端的一個請求被阻塞,并且直到服務(wù)端趕上并處理為止。

因此 systemd 先進行套接字的激活,然后開始服務(wù)的創(chuàng)建,使得所有的服務(wù)可以并行啟動,依賴的管理也變得多余,至少可以說是次要的,因為從服務(wù)的角度看,只要套接字是激活的,另一個服務(wù)有沒有啟動都沒有區(qū)別,這樣一種方式也使得程序更加地健壯,因為不論服務(wù)可用或不可用,甚至是崩潰,套接字都處于可用的狀態(tài),不會讓客戶端注意到丟失連接。

4. systemd 執(zhí)行單元--Unit 介紹

Unit 是 systemd 管理服務(wù)與資源的基本單元,可以簡單理解為 systemd 啟動后每次需要執(zhí)行的服務(wù),每次需要處理的資源,都被抽象為一個配置單元 Unit,保存在一個 Unit 文件里面。例如,當用戶登錄到優(yōu)麒麟操作系統(tǒng)時,systemd 會執(zhí)行 systemd-login.service 這個 Unit 文件來啟動 login 服務(wù),持續(xù)跟蹤用戶的會話、進程、空閑狀態(tài),為用戶分配一個 slice 單元;當用戶執(zhí)行睡眠操作時,systemd 會執(zhí)行 systemd-suspend.service 文件的 Unit,來啟動 systemd-sleep 服務(wù)執(zhí)行系統(tǒng)睡眠操作。Unit 文件可以根據(jù)其后綴名分為12種不同的類型,systemd 內(nèi)部給這12種類型的 Unit 定義了不同的全局模板,因此 systemd 的執(zhí)行流程為:

首先找到對應(yīng)的 Unit 文件,然后根據(jù) Unit 文件的類型匹配對應(yīng)的全局模板,再然后根據(jù)這個模板解析 Unit 文件,最后執(zhí)行 Unit 文件里的操作。接下來簡單介紹一下12種 Unit 文件類型:

(1)service:這是最明顯的單元類型,代表一個后臺守護進程,可以啟動、停止、重新啟動、重新加載守護進程,是最常用的一類 Unit 文件。

(2)socket:這個單元在文件系統(tǒng)或互聯(lián)網(wǎng)上封裝了一個套接字。目前 systemd 支持流、數(shù)據(jù)報和順序包類型的 AF_INET、AF_INET6、AF_UNIX 套接字。還支持經(jīng)典的 FIFO 作為傳輸。每個套接字單元都有一個匹配的服務(wù)單元,相應(yīng)的服務(wù)在第一個連接進入套接字時就會啟動,例如:nscd.socket 在傳入連接上啟動 nscd.service。

(3)device:這個單元封裝了 Linux 設(shè)備樹中的一個設(shè)備。如果設(shè)備通過 udev 規(guī)則為此標記,它將在 systemd 中作為設(shè)備單元公開。使用 udev 設(shè)置的屬性可用作配置源來設(shè)置設(shè)備單元的依賴關(guān)系。

(4)mount:這個單元封裝了文件系統(tǒng)層次結(jié)構(gòu)中的一個掛載點。systemd 監(jiān)控所有掛載點,也可用于掛載或卸載掛載點。systemd 會將/etc/fstab 中的條目都轉(zhuǎn)換為掛載點,并在開機時處理。

(5)automount:這個單元類型在文件系統(tǒng)層次結(jié)構(gòu)中封裝了一個自動掛載點。每個自動掛載單元都有一個匹配的掛載單元,當該自動掛載點被訪問時,systemd 就會執(zhí)行掛載點中定義的掛載行為。

(6)target:這種單元類型用于單元的邏輯分組:它本身并不做任何事情,它只是引用其他單元,從而可以一起控制。比如:想讓系統(tǒng)進入圖形化模式,需要運行許多服務(wù)和配置命令,這些操作都由一個個的配置單元表示,將所有這些配置單元組合為一個目標(target),就表示需要將這些配置單元全部執(zhí)行一遍以便進入目標所代表的系統(tǒng)運行狀態(tài)。

(7)snapshot:類似于 target 單元,snapshot 本身實際上不做任何事情,它們的唯一目的是引用其他單元??煺湛捎糜诒4婊蚧貪L init 系統(tǒng)的所有服務(wù)和單元的狀態(tài)。比如允許用戶臨時進入特定狀態(tài),例如“緊急外殼”,終止當前服務(wù),并提供一種簡單的方法返回之前的狀態(tài)。

(8)swap:和掛載配置單元類似,交換配置單元用來管理交換分區(qū)。用戶可以使用交換配置單元來定義系統(tǒng)中的交換分區(qū),可以讓這些交換分區(qū)在啟動時被激活。

(9)timer:定時器配置單元用來定時觸發(fā)用戶定義的服務(wù)操作,是一種基于定時器的服務(wù)激活,這類配置單元取代了 atd、crond 等傳統(tǒng)的定時服務(wù)。

(10)path:這類配置單元用來監(jiān)控指定目錄或者文件的變化,根據(jù)變化觸發(fā)其他配置單元服務(wù)的運行。

(11)scope:這個單元主要表示從 systemd 外部創(chuàng)建的進程。

(12)slice:此單元主要用于封裝管理一組進程資源占用的控制組的 slice 單元,也就是主要用于 cgroup,它通過在 cgroup 中創(chuàng)建一個節(jié)點實現(xiàn)資源的控制,一般包含 scope 與 service 單元。

下面通過藍牙服務(wù) bluetooth.service 介紹一下 Unit 文件的結(jié)構(gòu)。

優(yōu)麒麟(Ubuntu Kylin)

Unit 文件主要分為以下三個大的部分:

Unit 段:此部分所有 Unit 文件通用,用來定義 Unit 的元數(shù)據(jù)、配置以及與其他 Unit 的關(guān)系,Description 描述 Unit 文件信息,Documentation 表示指定服務(wù)的文檔,Condition 表示服務(wù)啟動的條件,有些 Unit 還包含 wants、before、after、require 字段,這些表示服務(wù)的一個依賴關(guān)系。

Install 段:此部分所有 Unit 文件通用,通常指定運行目標的 target,使得服務(wù)在系統(tǒng)啟動時自動運行。Wantedby、RequiredBy 與 Unit 段 Wants 字段類似,表示依賴關(guān)系,Alias 字段表示啟動運行時使用的別名。

service 段:服務(wù)(Service)類型的 Unit 文件特有的字段,用于定義服務(wù)的具體管理和執(zhí)行動作。其中包括 Type 字段,定義進程的行為,例如使用 fork()啟動,使用 dbus 啟動等等;ExecStart、ExecStartPre、ExecStartPos、ExecReload、ExecStop 分別表示啟動當前服務(wù)執(zhí)行的命令、啟動當前服務(wù)之前執(zhí)行的命令、啟動當前服務(wù)之后啟動的命令、重啟當前服務(wù)時執(zhí)行的命令、停止當前服務(wù)時執(zhí)行的命令。以上圖為例,啟動藍牙服務(wù)所需要執(zhí)行的命令為/usr/lib/bluetooth/bluetoothd。

相關(guān)字段更詳細的描述可以參考 freedesktop 的 man 手冊:https://www.freedesktop.org/software/systemd/man/systemd.unit.html 

https://www.freedesktop.org/software/systemd/man/systemd.service.html 

以優(yōu)麒麟操作系統(tǒng)為例,Unit 文件主要的存儲路徑如下:

system:

/etc/systemd/system/*

/run/systemd/system/*

/lib/systemd/system/*

user:

~/.config/systemd/user/*

/etc/systemd/user/*

$XDG_RUNTIME_DIR/systemd/user/*

/run/systemd/user/*

~/.local/share/systemd/user/*

/usr/lib/systemd/user/*


考慮篇幅問題,本期先帶來 systemd 的基礎(chǔ)介紹,下期將帶大家詳細了解開機啟動的過程中 systemd 的作用機制。