優化Linux 系統服務來提高引導速度

優化Linux 系統服務來提高引導速度

關鍵詞優化Linux    系統服務來提高引導速度                                          

本文向您描述瞭如何在不影響可用性的前提下加快 Linux 操作系統的引導速度。當然,這種方法要求您對系統服務及服務之間的依賴關係有所理解,如果它們可以並行啓動,就讓它們並行啓動而不是串行啓動。

    毫無疑問 Linux 是一個優秀的系統,但仍然無法擺脫一個常見的責難(尤其是來自具有 Microsoft Windows 背景的人),那就是 Linux 系統從按下“on”鍵開始到可以使用,需要的時間太長。其實他們說的沒錯,Linux 確實需要比較長的引導時間。

    在這裏我所描述的加快 Linux 引導速度的技術雖然理解起來很簡單,但真正實現卻需要謹慎行事。我希望 Linux 的發行商能採用這種方法,這樣用戶就可以省去那些配置任務。不過如果您喜歡冒險,請繼續閱讀本文。

寫在開始之前
    如果您想體驗一下這種方法,您首先必須得熟悉 Linux 的配置腳本。修改系統的啓動設置可能會帶來危險,甚至可能會導致您的系統無法啓動。如果出現這種情況,請重新啓動機器並進入單一用戶模式(運行級1),把您所做的修改還原回來,然後再重新啓動。永遠記住要備份您所修改過的所有文件,爲了防止最壞的情況發生,您還需要有至少一個系統備份的映像。

    我強烈建議您在考慮用我所建議的方法修改一個正式的系統之前,先去修改一個無關緊要的測試系統。如果您只有一臺機器,那麼您可以使用 UML (User Mode Linux) 這一非常有用的工具。UML是一個內核補丁,它可以將Linux內核編譯成爲一個二進制文件,然後您可以像運行一個普通的程序一樣去運行這個內核。也就是說,您可以在您的正常的系統之上以一個進程的方式來運行一個完整的 Linux 系統。您可以將其想象爲在一個正常的系統 運行一個 Linux 系統。(請參閱本文末尾的 參考資料,可以找到可以下載UML的站點以及 developerWorks網站上關於UML的教程)。

    使用UML您可以工作於一個測試系統,哪怕把這個測試系統完全破壞掉,也不會影響您正常的系統。

概述
    本文的第一部分介紹當 Linux 內核(Linux 機器的的“核心”)加載後,一個 Linux 系統怎樣在後臺啓動。然後介紹加快您的系統引導速度的技術。

    如果您對運行級和服務啓動腳本已經熟悉,您可能希望直接跳轉到 傳統服務框架的侷限。

Linux 引導次序和運行級

    一個 Linux 系統的引導過程可以分爲幾個階段。本文並不會解釋所有的不同階段,因爲我們所關心只是當內核加載後的那一個階段。

    您可以運行 /sbin/runlevel 命令來確定您的系統當前的運行級。(更多詳細信息請查閱 man runlevel)。

    當內核被加載並開始運行時會調用 /sbin/init 程序。這個程序以 root 身份運行,並且在開始引導時按照要求設定爲“運行級”。(更多關於 init 程序的詳細信息,請參考 man init)

什麼是運行級?

    一個 運行級僅僅是一個數字,Linux根據這個數字來區分不同類型的高層次配置,系統將按照不同的高層次配置來進行引導。由於絕大部分運行級數字都定義了明確的含義,因而它們基本上是“衆所周知”的。Red Hat Linux 系統的主要運行級見表1。

表 1. Red Hat Linux運行級

運行級 說明
0 關閉
1 單一用戶模式(一般僅用於管理目的)
2 多用戶模式,不允許使用網絡
3 多用戶模式,允許使用網絡
4 沒有用到的運行級
5 多用戶模式,允許使用網絡,X-Windows 方式(圖形登錄界面)
6 重新引導

init如何初始化系統
    init 通過一個ASCII配置文件(/etc/inittab)來確定如何改變運行級。通常,init 會根據這個配置文件去運行 /etc/rc.d/rc 腳本,並將運行級數字傳遞給這一腳本。

rc.sysinit 腳本

在 Red Hat 系統中,在運行 rc 腳本之前,init 將首先運行 /etc/rc.d/rc.sysinit 腳本,這個腳本執行那些必需的底層設置任務,比如設置系統時鐘,檢查磁盤錯誤,然後掛載文件系統。

在本文看來,正是從運行 rc 腳本開始,事情才變得有趣。

系統服務
    rc 腳本負責啓動用戶需要的所有服務。就像名字所描述的一樣,所謂服務就是系統提供的有用的工具。可能會有很多服務需要啓動。大部分的 Linux 系統會啓動 sshd(安全Shell服務)、syslog(系統日誌工具)和 lpd(打印服務),但還會有更多的服務需要啓動。比如,我的 Red Hat 9 系統現在運行着29個服務,但如果我把所有的服務都啓動,那麼我的系統中將會有近50服務在運行。

    還有一點很重要,我們應該明白有的服務可能只能由特定的運行級來啓動。比如,除了運行級5(多用戶圖形方式)以外,幾乎不會啓動某種形式的圖形服務,因爲其它所有的運行級都是非圖形方式的。接下來我們將深入討論這一問題。

服務程序在哪裏?

可選的服務程序目錄

在一些 Linux 系統中,服務程序有時候是在 /etc/init.d 目錄下。

    通常在 /etc/rc.d/init.d/ 目錄下可以找到服務程序。

    如果你瀏覽一下這個目錄,你就會發現相當多的(如果不是全部都是的話)服務程序實際上都是 shell 腳本,用於調用其他程序完成實際的工作。

rc 腳本如何知道在每個運行級下去運行哪些腳本?
    回顧一下,如果我們不希望在某個運行級下運行某個腳本,我們如何告訴系統這樣去做?答案是在 /etc/rc.d/ 目錄下,在這個目錄下,除了我們已經討論過的 init.d/ 目錄以外,還有一組目錄,每一個目錄對應一個運行級。這些目錄以 rc<runlevel>.d 的形式來命名,比如,對應運行級5的目錄爲 /etc/rc.d/rc5.d/ 。在這些rc.d目錄中,每一個目錄下都有一組符號鏈接,指向 /etc/rc.d/init.d 中的真正的服務程序。實際上,後邊我們會發現,每個服務事實上有兩個符號鏈接。

服務鏈接名
    這些指向實際服務程序的符號鏈接的名字很重要,它們遵循嚴格的命名約定,這樣 rc 腳本就知道如何處理它們。

    爲了便於標識,每個鏈接的名字都以它們所指向的服務的名字做爲後綴。

    前綴由兩部分構成:一個大寫字母,緊跟着是一個兩位的十進制數。前綴中的大寫字母是“S”(表示“啓動”),或者“K”(表示“殺死”,或者停止)。兩位數的大小範圍是自00到99。

服務鏈接名正則表達式

符號鏈接的名字可以用 egrep 正則表達式來描述,[SK][0-9]{2}[a-zA-Z]+。(更多詳細信息請參閱 man egrep)。

啓動和停止服務
    如果我們決定讓 Linux 機器引導到圖形模式(運行級5),當 init 調用 rc 腳本並傳遞給它運行級數字時,rc 腳本將到 /etc/rc.d/rc5.d/ 中查找,並且去運行它所能找到的所有符號鏈接(也就是說,它將運行每個鏈接指向的程序/腳本)。它將在兩個截然不同的階段來運行這些鏈接;首先它會執行所有以“K”開頭的鏈接,同時傳遞給它們參數“stop”。執行完以後,所有這些鏈接指向的服務都被停止。

    當 rc 腳本把所有需要停止的服務都停止後,它將去執行所有以“S”開頭的鏈接,同時傳遞給它們參數“start”。執行完以後,所以這些鏈接指向的服務都被啓動。rc 腳本也把參數“start”傳遞給每一個程序。

    rc 把參數“tart”或者“stop”傳遞給每一個服務程序,這樣做是爲了只用一個服務程序可以啓動或停止那個服務——服務程序根據傳遞給它的參數值分辨系統是正在引導還是正在關閉。

    有一個重要的方面我還沒有解釋——鏈接名的數字部分。在“S”或者“K”之後的兩位十進制數是 rc 腳本用來確定啓動鏈接(就是鏈接指向的服務)的 順序的。數字較小(比如00,01,等等)的鏈接在數字較大(99是最大的)鏈接之前運行。我們會在本文後邊的內容中再次提到這一重點問題。

    現在還迷惑嗎?清單1列出了運行級5對應目錄下的所有鏈接。當引導到運行級5的時候,最先被執行的鏈接將是 K05saslauthd,因爲它以“K”開頭,並且在所有的以“K”開頭的鏈接中兩位十進制數是最小。最先被執行的啓動鏈接將是 S05kudzu,因爲它以“S”開頭,並且在所有以“S”開頭的鏈接中兩位十進制數是最小的。最後一個運行的鏈接將是 S99local。


清單 1. 運行級5的指向服務程序的鏈接


# cd /etc/rc.d/rc5.d
# ls -al
total 8
drwxr-xr-x    2 root     root     4096 Jul 15 09:29 .
drwxr-xr-x   10 root     root     4096 Jun 21 08:52 ..
lrwxrwxrwx    1 root     root       19 Jan  1  2000 K05saslauthd -> ../init.d/saslauthd
lrwxrwxrwx    1 root     root       20 Feb  1  2003 K15postgresql -> ../init.d/postgresql
lrwxrwxrwx    1 root     root       13 Jan  1  2000 K20nfs -> ../init.d/nfs
lrwxrwxrwx    1 root     root       14 Jan  1  2000 K24irda -> ../init.d/irda
lrwxrwxrwx    1 root     root       17 Jan  1  2000 K35winbind -> ../init.d/winbind
lrwxrwxrwx    1 root     root       15 Jan  1  2000 K50snmpd -> ../init.d/snmpd
lrwxrwxrwx    1 root     root       19 Jan  1  2000 K50snmptrapd -> ../init.d/snmptrapd
lrwxrwxrwx    1 root     root       16 Jun 21 09:43 K50vsftpd -> ../init.d/vsftpd
lrwxrwxrwx    1 root     root       16 Jun 21 08:57 K73ypbind -> ../init.d/ypbind
lrwxrwxrwx    1 root     root       14 Jun 21 08:54 K74nscd -> ../init.d/nscd
lrwxrwxrwx    1 root     root       18 Feb  8 11:15 K92iptables -> ../init.d/iptables
lrwxrwxrwx    1 root     root       19 Feb  1  2003 K95firstboot -> ../init.d/firstboot
lrwxrwxrwx    1 root     root       15 Jan  1  2000 S05kudzu -> ../init.d/kudzu
lrwxrwxrwx    1 root     root       14 Jun 21 08:55 S09isdn -> ../init.d/isdn
lrwxrwxrwx    1 root     root       17 Jan  1  2000 S10network -> ../init.d/network
lrwxrwxrwx    1 root     root       16 Jan  1  2000 S12syslog -> ../init.d/syslog
lrwxrwxrwx    1 root     root       17 Jan  1  2000 S13portmap -> ../init.d/portmap
lrwxrwxrwx    1 root     root       17 Jan  1  2000 S14nfslock -> ../init.d/nfslock
lrwxrwxrwx    1 root     root       18 Jan  1  2000 S17keytable -> ../init.d/keytable
lrwxrwxrwx    1 root     root       16 Jan  1  2000 S20random -> ../init.d/random
lrwxrwxrwx    1 root     root       16 Jun 21 08:52 S24pcmcia -> ../init.d/pcmcia
lrwxrwxrwx    1 root     root       15 Jan  1  2000 S25netfs -> ../init.d/netfs
lrwxrwxrwx    1 root     root       14 Jan  1  2000 S26apmd -> ../init.d/apmd
lrwxrwxrwx    1 root     root       16 Jan  1  2000 S28autofs -> ../init.d/autofs
lrwxrwxrwx    1 root     root       14 Jan  1  2000 S55sshd -> ../init.d/sshd
lrwxrwxrwx    1 root     root       20 Jan  1  2000 S56rawdevices -> ../init.d/rawdevices
lrwxrwxrwx    1 root     root       16 Jan  1  2000 S56xinetd -> ../init.d/xinetd
lrwxrwxrwx    1 root     root       14 Feb  1  2003 S58ntpd -> ../init.d/ntpd
lrwxrwxrwx    1 root     root       13 Jun 21 10:42 S60afs -> ../init.d/afs
lrwxrwxrwx    1 root     root       13 Jan  1  2000 S60lpd -> ../init.d/lpd
lrwxrwxrwx    1 root     root       16 Feb  8 17:26 S78mysqld -> ../init.d/mysqld
lrwxrwxrwx    1 root     root       18 Jan  1  2000 S80sendmail -> ../init.d/sendmail
lrwxrwxrwx    1 root     root       13 Jan  1  2000 S85gpm -> ../init.d/gpm
lrwxrwxrwx    1 root     root       15 Mar 22 08:24 S85httpd -> ../init.d/httpd
lrwxrwxrwx    1 root     root       15 Jan  1  2000 S90crond -> ../init.d/crond
lrwxrwxrwx    1 root     root       13 Jan  1  2000 S90xfs -> ../init.d/xfs
lrwxrwxrwx    1 root     root       17 Jan  1  2000 S95anacron -> ../init.d/anacron
lrwxrwxrwx    1 root     root       13 Jan  1  2000 S95atd -> ../init.d/atd
lrwxrwxrwx    1 root     root       15 Jun 21 08:57 S97rhnsd -> ../init.d/rhnsd
lrwxrwxrwx    1 root     root       14 Jul 15 09:29 S98wine -> ../init.d/wine
lrwxrwxrwx    1 root     root       13 Feb  8 17:26 S99db2 -> ../init.d/db2
lrwxrwxrwx    1 root     root       11 Jun 21 08:52 S99local -> ../rc.local
# 

    這看起來好象是非常複雜的系統,但實際上它提供了極好的靈活性,因爲如果您想臨時禁止某個特定運行級中的服務,只要把適當的符號鏈接刪除即可。不過,手工管理這些鏈接可能會讓人感覺厭煩,並且容易出錯(尤其當您累了的時候),所以可以採用一個相對好一些的方法,使用 chkconfig 命令。

如果您有一個新版本的 chkconfig ,您會在主輸出的最後一部分看到有關 xinetd (Internet services daemon)的配置。爲了減化說明,此部分沒有列入清單2中。

如何找出激活的服務
想查看您已經激活了多少服務,運行這個命令:

/sbin/chkconfig --list

清單 2列出了這個命令的輸出。您可以看到,每一行有八列。

chkconfig 命令還可以用來切換任何一個服務的開或關。詳細信息請參考手冊頁(man chkconfig)。


清單 2. chkconfig --list|sort的輸出


afs             0:off   1:off   2:off   3:on    4:off   5:on    6:off
anacron         0:off   1:off   2:on    3:on    4:on    5:on    6:off
apmd            0:off   1:off   2:on    3:on    4:on    5:on    6:off
atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
autofs          0:off   1:off   2:off   3:on    4:on    5:on    6:off
crond           0:off   1:off   2:on    3:on    4:on    5:on    6:off
db2             0:off   1:off   2:off   3:on    4:off   5:on    6:off
firstboot       0:off   1:off   2:off   3:off   4:off   5:off   6:off
gpm             0:off   1:off   2:on    3:on    4:on    5:on    6:off
httpd           0:off   1:off   2:off   3:off   4:off   5:on    6:off
iptables        0:off   1:off   2:off   3:off   4:off   5:off   6:off
irda            0:off   1:off   2:off   3:off   4:off   5:off   6:off
isdn            0:off   1:off   2:on    3:on    4:on    5:on    6:off
keytable        0:off   1:on    2:on    3:on    4:on    5:on    6:off
kudzu           0:off   1:off   2:off   3:on    4:on    5:on    6:off
lpd             0:off   1:off   2:on    3:on    4:on    5:on    6:off
mysqld          0:off   1:off   2:off   3:on    4:off   5:on    6:off
netfs           0:off   1:off   2:off   3:on    4:on    5:on    6:off
network         0:off   1:off   2:on    3:on    4:on    5:on    6:off
nfs             0:off   1:off   2:off   3:off   4:off   5:off   6:off
nfslock         0:off   1:off   2:off   3:on    4:on    5:on    6:off
nscd            0:off   1:off   2:off   3:off   4:off   5:off   6:off
ntpd            0:off   1:off   2:off   3:on    4:off   5:on    6:off
pcmcia          0:off   1:off   2:on    3:on    4:on    5:on    6:off
portmap         0:off   1:off   2:off   3:on    4:on    5:on    6:off
postgresql      0:off   1:off   2:off   3:off   4:off   5:off   6:off
random          0:off   1:off   2:on    3:on    4:on    5:on    6:off
rawdevices      0:off   1:off   2:off   3:on    4:on    5:on    6:off
rhnsd           0:off   1:off   2:off   3:on    4:on    5:on    6:off
saslauthd       0:off   1:off   2:off   3:off   4:off   5:off   6:off
sendmail        0:off   1:off   2:on    3:on    4:on    5:on    6:off
snmpd           0:off   1:off   2:off   3:off   4:off   5:off   6:off
snmptrapd       0:off   1:off   2:off   3:off   4:off   5:off   6:off
sshd            0:off   1:off   2:on    3:on    4:on    5:on    6:off
syslog          0:off   1:off   2:on    3:on    4:on    5:on    6:off
vsftpd          0:off   1:off   2:off   3:off   4:off   5:off   6:off
winbind         0:off   1:off   2:off   3:off   4:off   5:off   6:off
wine            0:off   1:off   2:on    3:on    4:on    5:on    6:off
xfs             0:off   1:off   2:on    3:on    4:on    5:on    6:off
xinetd          0:off   1:off   2:off   3:on    4:on    5:on    6:off
ypbind          0:off   1:off   2:off   3:off   4:off   5:off   6:off

   清單 2中第一列是服務的名字,接下來的列是運行級和每一個運行級中服務的狀態。例如,ntpd (Network time daemon)服務被配置爲只在運行級3中(多用戶,無圖形)和運行級5(多用戶,有圖形)中啓動,sshd 服務在運行級2,3,4和5中都被切換到開的狀態。

    注意在運行級0和6中沒有一個服務要啓動。回顧表 1,原因顯而易見。運行級1表示要關閉或停止系統,因此在機器將要“關閉”時,您不會想要 啓動任何服務。運行級6中也是如此。

    運行級1——“單一用戶模式”——是一個特別的運行級,一般在系統出問題的時候使用。一直以來,在運行級1中運行的唯一一個應用程序是 shell,允許超級用戶來修復系統或者讓超級用戶在一個安全的環境中修改系統。這樣是安全的——就像它的名字“單一用戶模式”的含意一樣——只有超級用戶可以訪問系統。並且,聯網是禁用的,所以沒有人可以遠程登錄。如表 1所示,單一用戶模式中運行的唯一一個服務是keytable,這樣使得超級用戶的鍵盤可以正常使用。

激活服務與運行服務的對比
有時服務會由於某種原因無法啓動,用下面這個命令查看當前有哪些服務正在運行:

/sbin/service --status-all

     這個命令將爲每個服務輸出一行或多行,指出每個服務是否在運行,如果在運行,則列出服務的一些特定的輸出,比如服務運行的PID(進程號)。service 命令沒有手冊頁,但是您可以在運行這個命令時使用--help 選項,您就可以得到有關它的操作的一些幫助信息。

傳統服務框架的缺陷

    關鍵的是,只有當配置中的所有服務都啓動以後,您纔可以登錄進入您的 Linux 系統。等待50個服務啓動可能會需要若干分鐘,而這本來應該是您享用Linux系統的時間。

     我已經找到了一個加速這個過程的方法。注意這種方法不會停止任何服務。不管怎樣,停掉那些不用的服務是很明智的,不僅是因爲這樣可以加快引導的速度(在機器可以登錄之前需要運行的服務少了),而且,由於很多服務要以 root 用戶身份來運行,停掉不用的服務會減少您的安全隱患。

    扼要重述一下,當一個 Linux 系統引導時,它以一種連續的方式來運行所有的某個運行級所配置的所有服務—— 一個接一個地。這是一個耗時的操作。

    或許一個很明顯的加快服務啓動速度的方法是並行地啓動所有的服務,這樣它們就可以同時啓動。不幸的是,雖然這聽起來很吸引人,卻不可行。原因是各個服務之間存在依賴的關係。Linux沒有把這些依賴關係完全顯式地表示出來,但是事實上這些依賴關係是存在的。還記得我們先前討論的關於鏈接名字格式的問題嗎?在 “S”和“K”之後的兩位數決定了鏈接(也就是它們指向的服務)的運行順序。這些數字確定了一個硬性的順序,這樣一定程度上也強化了服務之間的依賴關係。

服務之間的依賴關係

    回顧 清單 1,我們可以看到 network 服務(S10network)將在ntpd服務(S58ntpd)之前運行。這是我們所期望的,因爲 ntpd 服務要求網絡可達,以使它可以連接一個本地時間服務器。不幸的是,這個硬性的順序並不能告訴我們足夠的信息,並且會讓人誤解。例如,在 清單 1中我們可以看到 lpd 服務(S60lpd)將在 network 服務之後運行。雖然這樣對那些連接到網絡並且使用網絡打印機的 Linux 系統來說是正確的,但是這並不說明當背板上有一個 inkjet 打印機連接到本地系統時,lpd 服務還是必須要在 network 服務之後運行。實際上,在這種情況下,在啓動 network 之前先啓動 lpd 會更好一些。

再來看另外一個例子:crond (cron daemon)服務 (在 清單 1中的 S90crond)也是在 network 啓動之後運行。可是,如果您沒有使用遠程機器文件的 cron 文件,那麼就應該讓 crond 在 network 之前啓動。

    由於我剛纔介紹的 Linux 下啓動服務的傳統方法有一定的侷限性,往往傾向於“安全第一",讓所有的重要的服務先啓動,然後再啓動餘下的那些。

    所以,儘管我們不能並行地啓動 所有的服務,但我們可以並行地啓動那些 相互間沒有依賴關係的服務。當這些相互間無依賴的服務啓動以後,我們可以啓動那些所有依賴條件已經滿足(也就是說,那些服務所依賴的服務已經啓動)的服務。然後重複這一過程,直到所有服務全部啓動。

    這個看起來是一個複雜的問題,不過幸運的是,已經有一個現成的可以用來解決這個問題的程序。這個程序不是別的,正是 make。

    通常當編譯軟件時,make 會提供我們所需要的嚴密的框架。所有我們要做的就是告訴 make 什麼是服務之間的依賴;它可以去做所有的計算交叉依賴的艱難工作,並且,使用它的鮮爲人知的標記 -j ,它可以作爲許多"作業"而 同步運行。

得出服務間依賴關係
    如先前我間接提到的,傳統的 Linux 系統沒有顯式地表示服務間的依賴關係,所以現在我們不得不自己去做一些艱難的工作,得出這些依賴關係。這可能會需要一段時間,因爲您可能都不知道每個服務在做什麼,更別提服務之間的關係了。然而,如果您沒有完成這些工作,這種方法對您來說沒有任何益處。(如前面所提到的,如果這種方法有實用價值,希望 Linux 發行商可以採用它,並且爲我們做這些艱難的工作。)

認識您的服務

如果當您運行命令 /sbin/chkconfig --list時,您有可能會遇到一些您所不認識的服務,那麼花一些時間去弄明白它。一個簡單的方法是讀那些控制相應服務的腳本中開頭處的註釋。
這樣您就可以把不用的那些工具所對應的服務關掉。即便是您需要它,這樣您也可以更加了解您的系統。

    現在,我們來做一個簡單的實例。我們都知道,ntpd 服務需要網絡,這說明 ntpd 服務依賴於network 服務。在 make 語法中這個依賴關係這樣表示:

ntpd : network

    我們還可以確定 netfs 服務(掛載我們所需要的所有NFS目錄)依賴於網絡。在我的系統(您的可能會不一樣)上,autofs 服務(自動掛載網絡文件系統)也依賴於 network 服務,因爲我曾經自動掛載遠程文件系統(您可能掛載光驅或者軟驅)。我們的“依賴表”現在是這樣:

 


ntpd  : network
          
netfs : network
autofs : network

    這看起來沒什麼,但是您知道這意味着什麼嗎?這意味着一旦 network 服務啓動完成,我們可以 並行地啓動 ntpd,netfs 和 autofs 服務。

     做爲一個特定的例子,假設所有的服務都需要10秒才能啓動。用傳統的服務啓動方法,啓動 network,ntpd,netfs 和 autofs 服務需要40秒。而用這種技術,只需要20秒——節約的50%的時間。

    爲什麼會這樣?好了請看,network 服務啓動需要10秒時間,但是(因爲當 rc 腳本在運行時,機器處於完全多任務的狀態)其餘三個服務可以 同時啓動,所以這三個服務 合起來的啓動時間是10秒。

    事實上,大部分服務需要的啓動時間可能不是10秒,但是既然每一個服務要做一些完全不同的事情,啓動它們所需要的時間會很可觀。

樣例實現
    我在 參考資料部分提供的壓縮文件中有一個使用上述技術的樣例實現。包括一個修改過的用於調用 make 命令的 rc 腳本,以及樣例GNU makefile文件,分別是 runlevel.mk,start5.mk和stop5.mk。makefile 文件 runlevel.mk 是控制程序,start5.mk 文件和stop5.mk 文件分別是運行級5時啓動和停止服務時的服務依賴描述文件。

    注意所給出的啓動和停止 makefile 文件提供的不是完全的服務間依賴關係列表,而僅僅是一個例子。同時也要注意,如果您不修改這些文件就在您的系統上使用,幾乎不可能成功,因爲您的服務列表可能和我的並不一樣。

結束語(以及一些補充說明)
    我提出了一種用來加快 Linux 機器引導速度的方法。這種方法允許系統在啓動服務時啓動順序中靠後的部分服務並行啓動,而不是以傳統的串行方式啓動,以實現引導的加速。這種方法在理論上沒有問題,並且可以利用現有的系統工具實現。

     這種方法的效率取決於需要啓動的服務的數量和每個服務啓動所需要的時間。並行的可行性主要取決於服務間的依賴關係。對於某些系統來說,使用這種方法可能只會有很小的改進,但對於其他系統,它可能會顯著地影響引導速度。可以這樣理解,每個系統都有不同的一組服務被激活,並且每一個服務需要不同的時間來啓動。再強調一次,要使用這種方法,您需要確定 您的特定系統的服務之間的依賴關係。

補充說明:

  • 一些服務程序僅僅是在後臺運行一個程序,它們自己就退出了(也就是說,服務程序結束了,但是真實的工作仍然在後臺進行)。這說明了一個事實,那就是傳統的系統是不完善的,這種服務程序編寫者試圖在現有框架的界限內減少一些時鐘週期。採用本文描述的這種方法將會使依賴關係更加顯式化,不需要服務編寫者再去“欺騙”。這種方法考慮到在這些服務程序之外建立一個更爲高效的框架。
  • 當您希望“交互式”引導您的系統時,這裏所提到的技術不再適用,因爲您通常是當系統某些地方出錯的時候纔會這樣去做;在這種情況下,您可能希望串行地去啓動所有的服務以找出出錯的原因。不過,修改系統的啓動過程,來讓用戶在系統引導來選擇是以串行的方式(允許交互的服務啓動)或者“並行”的服務啓動方式,是容易實現的。
  • 採用這種方法可能還需要更深入的考慮,因爲如果傳統的系統和新的系統都提供給用戶,將需要同步維持兩組關於服務如何啓動的信息(有序的 rc.d/ 鏈接文件和運行級 make 文件)。一個更好一些的解決方案是 Linux 發行版本能從 makefile 文件自動生成鏈接文件,因爲 makefile 文件比鏈接文件記錄了更多的關於服務的信息。
  • 這個系統可能對一個專用的服務器來說並不適合,因爲當一個服務發生錯誤時,管理員希望能在錯誤發生時在控制檯中馬上可以看到這個錯誤。不過,對於普通的終端用戶來說,並行化的方法可以在允許用戶查看是否有問題發生的前提下顯著地加快引導速度。
  • 有趣的是,儘管我提出的這種方法從傳統觀點來看不是“類似Linux的”,但 Linux 基礎標準 (LSB,Linux Standards Base)看起來並沒有要指定 init.d 腳本的運行順序,所以這種方法有可能被 Linux 發行商所採用,而且使之仍然符合 LSB。這對用戶來說是一個好消息,如前面所提到的,因爲發行商可以爲我們計算出所有的軟件包之間的依賴關係。
  • 有一種方法可能更爲大膽,那就是 /etc/inittab 文件中的“action field”的“wait”修改爲“once”。這樣用戶在服務啓動完成之前就可以登錄。不過,這已經超出了本文的範圍。要得到更詳細的信息請查閱 man inittab,並且請記住,UML是您的好幫手。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章