毫無疑問 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.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 如果您有一個新版本的 chkconfig ,您會在主輸出的最後一部分看到有關 xinetd (Internet services daemon)的配置。為了減化說明,此部分沒有列入清單2中。 如何找出激活的服務 想查看您已經激活了多少服務,運行這個命令: /sbin/chkconfig --list 清單 2 列出了這個命令的輸出。您可以看到,每一行有八列。 chkconfig 命令還可以用來切換任何一個服務的開或關。詳細信息請參考手冊頁(man chkconfig)。 清單 2. chkconfig --listsort的輸出 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是您的好幫手。