乾貨分享 | Systemd 技術原理&實踐(下)

systemd 文章續集來啦,上期我們介紹了 systemd 的基本概念 ,本期就爲大家詳細講解 systemd 相關的運行邏輯,希望能對研究系統資源優化的優客有所幫助。

systemd 時代的開機啓動流程

在 systemd 作爲系統的 init 程序的時代下,Linux 系統的啓動流程可以大致分爲 6 個階段:BIOS 自檢階段、GRUB 引導階段、kernel 內核加載階段、initrd 虛擬根文件系統階段、systemd 初始化階段、終端登錄階段。每個階段都各司其職,爲下一個階段的進行做鋪墊,相互聯繫,缺一不可。接下來對每個階段做一下介紹:

1

BIOS 自檢階段

從我們啓動計算機從按下電源鍵開始,計算機開始通電,然後系統就開始加載主板內存上的第一段代碼:BIOS,系統進入 BIOS 自檢階段。

BIOS 爲基本輸入輸出系統,全稱 Basic Input Output System,它燒錄在主板的內存上,其中的內容只能讀不能改,如果要進行更改只能重新燒錄到主板的內存上。BIOS 在開機階段最主要的功能爲上電自檢,它會對主板上接入的硬件設備一個個進行檢查,例如檢查 CPU、主板、內存、軟硬盤系統、鍵盤、光驅等等硬件是否接入正常,有無故障,當某一些主要的硬件(例如 CPU、內存等)出現問題時,BIOS 就會報錯,無法繼續啓動系統。我們在啓動電腦時聽到的滴滴的聲音就是 BIOS 蜂鳴器發出的聲音,當硬件出問題的時候就可以聽到它蜂鳴器響兩到三聲報錯,系統就無法進行下一步的啓動。

BIOS 檢查完所有硬件狀態並狀態無誤的時候,就會按照設置的啓動順序去找相應的啓動盤,然後引導系統進入相應的啓動盤繼續啓動系統。有過刷機經驗的朋友應該知道在系統啓動時按 F12 或者 delete 鍵就會進入 BIOS 界面,然後就會去選擇相應的啓動盤進行刷機,啓動盤可以是裝機 U 盤、光驅,也可以是已經裝了系統的磁盤等等,BIOS 可以設置默認的啓動順序,例如:可以設置 U 盤爲第一啓動項,開機啓動時 BIOS 就會引導系統去找 U 盤對應的硬件接口,當找不到 U 盤時,BIOS 會繼續嘗試第二啓動項,當選擇好了啓動項時,系統進入相應的啓動盤,並開始執行啓動盤中第一塊磁盤第一個扇區的代碼,至此 BIOS 自檢階段結束。

2

GRUB 引導階段

GRUB 是 GRand Unified Bootloader 的縮寫,它是一個多重操作系統的管理器,存放在第一個磁盤的第一個扇區的主引導扇區裏面,如果你的電腦裏面裝了多個系統,例如 Linux 系統和 Windows 系統,那麼你可以通過 GRUB 來移動光標選擇自己想要進入的系統,選擇好系統以後 GRUB 就會根據系統分區表裏找到對應系統所在的磁盤分區,加載相應的 grub.cfg 配置文件,通過配置文件,加載 /boot 分區的文件系統驅動,然後在文件系統中找到系統內核,把內核加載進來並啓動,最後把系統的控制權交給內核,至此 GRUB 引導階段結束。

GRUB 除了引導系統這一主要功能外,還可以通過 grub.cfg 配置文件來實現其他的一些功能。grub.cfg 配置文件存放在 /boot/grub/目錄下,配置文件中,Linux 參數表示系統啓動時對應加載的內核,當系統裏存放了多個內核、或者在你電腦上重新修改編譯了新的內核的時候,可以配置此項來選擇相應的內核進行加載;quiet 參數類似於 loglevel 參數,用來配置日誌啓動的等級;splash 參數用來配置相應的啓動動畫等等。

3

Kernel 內核加載階段

在講解內核的啓動之前,先簡單介紹一下 Linux 內核。Linux 內核是一種宏內核,運行在單一地址空間的單一的程序,把系統的進程線程管理、內存管理、文件系統、驅動管理、網絡管理等一些基本功能集中在一起,內核中的每一個函數都可以訪問到其內核的其他部分,不同於微內核(代表:Windows 系統),微內核則是將這些功能獨立的劃分成不同的服務,服務之間通過通訊接口與中心內核通訊。

在結束了 GRUB 引導階段,內核拿到系統的控制權後,首先開始初始化系統中各種設備的相關配置工作,其中包括 CPU、I/O 設備、存儲設備的初始化等等,其次,內核創建內核態的 kernel_init 的進程,然後找到 initrd 文件並解壓,加載 initrd 虛擬根文件系統中的驅動程序完成相關硬件的初始化,最後調用 initrd 虛擬根文件系統的 init 腳本,至此,內核在系統啓動過程中的作用基本上就已經完成,內核開始等待 initrd 執行 init 進程,內核加載階段結束。

4

Initrd 虛擬根文件系統階段

initrd(Initial RAM Disk)它是一個虛擬的根文件系統,在 GRUB 階段被拷貝到內存,在內核中被解壓,是一個臨時的虛擬根文件系統,對其進行解壓後可以看到它的目錄結構和實際的根文件系統類似,並且包含了些驅動程序,下圖爲解壓麒麟 initrd.img 5.4.18-32 版本下的虛擬根文件系統的目錄結構:

由於內核爲了精簡,只保留了最基本的模塊,因此沒有各種設備硬件的驅動程序,這些驅動程序就存放在了 initrd 裏面,內核啓動的時候,就從 initrd 中加載必要的驅動模塊,完成硬件的初始化工作,接着,內核就開始執行虛擬根文件系統裏的 init 程序,即虛擬根文件系統下的 systemd 程序,systemd 就作爲內核的子程序,拿到了系統的控制權,開始做一些系統初始化方面的工作。

通過上面的描述,可以總結一下,虛擬根文件系統的階段可以大致的分爲:內核加載 initrd 裏面的驅動程序、虛擬根文件系統下的 systemd 程序加載這兩個過程,因此也可把虛擬根文件系統階段分別歸到內核加載階段與 systemd 初始化階段兩個裏面,是與上下兩個階段重合的一個階段。此外,initrd 還提供了美化啓動圖形界面的功能,用來遮蓋系統啓動過程中的 log 日誌輸出,提升用戶的體驗。當 initrd 下的 systemd 進程完成環境的初始化,系統切換到真正的根文件系統的時候,initrd 階段結束。

5

systemd 初始化階段

systemd 是 system deamon 的簡稱,是一個 Linux 系統基礎組件的集合,提供了系統與服務的管理,是 pid 爲 1 的 init 進程,是所有進程的父進程。需要詳細瞭解 systemd 進程的小夥伴可以閱讀上一篇文章:systemd 介紹,這裏重點講解一下 systemd 開機過程中所做的事情。

通過前面的描述,我們可以把 systemd 分爲兩個階段:虛擬根文件系統階段與實根文件系統階段。內核通過解壓 initrd 文件得到虛擬根文件系統,然後執行虛擬根文件系統下的 init 程序來啓動 systemd,systemd 作爲內核的子進程在虛擬根文件系統下開始運行。虛擬根文件下的 systemd 首先對目前的系統進行一些檢查,例如判斷系統的運行狀態是 user 態還是 system 態,系統是正常的啓動狀態還是異常出錯後的重啓狀態等等,然後進行一些系統的初始化配置,包括:環境變量的配置、日誌的相關配置等,接着對一些關鍵的文件系統進行掛載,主要包括 /proc、/sys、/dev、/var 這些基本的文件系統目錄,到這一步後,systemd 就開始爲切換實根文件目錄做準備,保存一些已經配置的項目,並進行一些環境的適配之後,systemd 執行 setsid()系統調用脫離內核控制,成爲一個完全獨立的父進程,至此 systemd 的虛擬根文件系統階段結束,systemd 進入到實根文件系統階段。

在實根文件系統階段,systemd 首先進行一些切換後的環境適配,然後開啓日誌終端的功能,並把系統啓動時臨時保存在內核中的日誌提取出來,整理後存放到相應的日誌文件中,下一步,systemd 開始進行一些系統能力的獲取與系統相關的初始化與配置,例如:CPU 親和力的獲取、主機名的配置、系統 ID 的配置,cgroup 控制器的掛載、迴環網絡的配置等,完成以上的這些所有初始化工作後,systemd 作爲 PID 爲 1 的守護進程,開始了各個系統服務的創建與管理工作,根據相應 Unit 配置單元文件執行相應的系統服務,通過各個服務逐步完成系統的啓動工作。systemd 執行 Unit 的順序大致可以分爲 sysinit.target->basic.target->default.target,其中 sysinit.target 與 basic.target 主要用來啓動一些系統初始化相關的一些服務與執行一些開機啓動早期的一些任務,default.target 則指向不同的“運行級別”target 文件,如果是進入命令行模式則指向 multi-user.target 文件,如果是進入圖形界面模式則指向 graphical.target 文件。至此,systemd 開機啓動階段的工作完成。

6

終端登錄階段

在完成了 systemd 初始化階段以後,系統根據配置的運行級別,進入不同的登錄界面,下面主要從圖形登錄界面進行介紹。在優麒麟操作系統中,systemd 之後的啓動流程主要如下:systemd->lightdm->Xorg->lightdm-greeter->ukui-greeter->ukui-session,在優麒麟的終端通過 pstree 命令可以看到如下兩個進程樹:

lightdm 是一個全新的、輕量的 Linux 桌面的桌面顯示管理器,它首先會拉起 Xorg,Xorg 是一個顯示的後臺,負責屏幕的繪製,然後 lightdm 還會拉起 lightdm-greeter,lightdm-greeter 是 lightdm 的子進程,它會拉起 ukui-greeter 進程,ukui-greeter 是登錄界面進程,因此 ukui-greeter 起來以後,系統進入到登錄界面,當輸入登錄的用戶名與密碼,用戶名與密碼效驗通過以後,lightdm 建立個人的 ukui-session 桌面窗口管理器進程,至此,終端登錄階段結束,系統完成啓動。

systemd 相關命令

systemd 提供了 systemctl 相關命令,用於管理系統,下面對一些基礎常用命令進行介紹:

1

系統管理命令**,控制系統電源狀態******

# 重啓系統

$ sudo systemctl reboot

# 關閉系統,切斷電源

$ sudo systemctl poweroff

# 暫停系統,使系統進入睡眠狀態

$ sudo systemctl suspend

# 讓系統進入冬眠狀態

$ sudo systemctl hibernate

# 讓系統進入交互式休眠狀態

$ sudo systemctl hybrid-sleep

2

systemd-analyze 命令**,用於查看啓動耗時,可用來分析系統的啓動效率******

#查看啓動耗時

$ systemd-analyze

#查看每個服務的啓動耗時

$ systemd-analyze blame

#顯示瀑布狀的啓動過程流

$ systemd-analyze critical-chain

#顯示指定服務的啓動流

$ systemd-analyze critical-chain atd.service

3

hostnamectl 命令**,**用於查看當前主機的信息

#顯示當前主機的信息

$ hostnamectl

#設置主機名

$ sudo hostnamectl set-hostname rhel7

4

Unit 相關命令**,用來管理 Unit 配置單元******

#列出正在運行的 Unit

$ systemctl list-units

#列出所有 Unit,包括沒有找到配置文件的或者啓動失敗的

$ systemctl list-units --all

#列出所有沒有運行的 Unit

$ systemctl list-units --all --state=inactive

#列出所有加載失敗的 Unit

$ systemctl list-units --failed

#列出所有正在運行的、類型爲 service 的 Unit

$ systemctl list-units --type=service

#立即啓動一個服務

$ sudo systemctl start apache.service

#立即停止一個服務

$ sudo systemctl stop apache.service

#重啓一個服務

$ sudo systemctl restart apache.service

#殺死一個服務的所有子進程

$ sudo systemctl kill apache.service

#重新加載一個服務的配置文件

$ sudo systemctl reload apache.service

#重載所有修改過的配置文件

$ sudo systemctl daemon-reload

#顯示某個 Unit 的所有底層參數

$ systemctl show httpd.service

#顯示某個 Unit 的指定屬性的值

$ systemctl show -p CPUShares httpd.service

#設置某個 Unit 的指定屬性

$ sudo systemctl set-property httpd.service CPUShares=500

5

日誌管理**,用來查看和過濾系統日誌******

#查看所有日誌(默認情況下 ,只保存本次啓動的日誌)

$ sudo journalctl

#查看內核日誌(不顯示應用日誌)

$ sudo journalctl -k

#查看系統本次啓動的日誌

$ sudo journalctl -b

$ sudo journalctl -b -0

#查看上一次啓動的日誌(需更改設置)

$ sudo journalctl -b -1

#查看指定時間的日誌

$ sudo journalctl --since="2012-10-30 18:17: 16"

$ sudo journalctl --since "20 min ago"

$ sudo journalctl --since yesterday

$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"

$ sudo journalctl --since 09:00 --until "1 hour ago"

#顯示尾部的最新 10 行日誌

$ sudo journalctl -n

#顯示尾部指定行數的日誌

$ sudo journalctl -n 20

#實時滾動顯示最新日誌

$ sudo journalctl -f

#查看指定服務的日誌

$ sudo journalctl /usr/lib/systemd/systemd

#查看指定進程的日誌

$ sudo journalctl _PID=1

#查看某個路徑的腳本的日誌

$ sudo journalctl /usr/bin/bash

#查看指定用戶的日誌

$ sudo journalctl _UID=33 --since today

#查看某個 Unit 的日誌

$ sudo journalctl -u nginx.service

$ sudo journalctl -u nginx.service --since today

#實時滾動顯示某個 Unit 的最新日誌

$ sudo journalctl -u nginx.service -f

#查看指定優先級(及其以上級別)的日誌,共有8級

# 0: emerg

# 1: alert

# 2: crit

# 3: err

# 4: warning

# 5: notice

# 6: info

# 7: debug

$ sudo journalctl -p err -b

#日誌默認分頁輸出,--no-pager 改爲正常的標準輸出

$ sudo journalctl --no-pager

#顯示日誌佔據的硬盤空間

$ sudo journalctl --disk-usage

#指定日誌文件佔據的最大空間

$ sudo journalctl --vacuum-size=1G

#指定日誌文件保存多久

$ sudo journalctl --vacuum-time=1years

END

關於 systemd 的完整介紹可以參考 systemd 官網手冊:https://www.freedesktop.org/software/systemd/man/index.html

以及 systemd 的官網中文翻譯手冊:

http://www.jinbuguo.com/systemd/systemd.index.html

systemd 源碼地址:

https://launchpad.net/ubuntu/+source/systemd

https://github.com/systemd/systemd

以上就是開機啓動的過程中 systemd 的作用機制介紹,如果有什麼問題和建議,歡迎留言或加入優麒麟交流羣一同探討哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章