版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
Linux系統(tǒng)架構(gòu)和應(yīng)用技巧目錄\h第1章你必須知道的!Linux內(nèi)部結(jié)構(gòu)\h1.1Linux的三大基礎(chǔ):磁盤、進(jìn)程、內(nèi)存\h1.2磁盤和文件\h1.2.1磁盤的3D參數(shù)\h1.2.2新舊分區(qū)表\h1.2.3文件系統(tǒng)和I/O子系統(tǒng)\h1.3控制進(jìn)程就等于控制Linux\h1.3.1fork和exec分別是進(jìn)程的分身和變身\h1.3.2作業(yè)控制中的各項任務(wù)處理\h第2章別說缺少機器!虛擬化基礎(chǔ)設(shè)施環(huán)境的構(gòu)建\h2.1基礎(chǔ)設(shè)施工程師的成長來自于日常積累\h2.2LinuxKVM虛擬網(wǎng)絡(luò)\h2.2.1虛擬網(wǎng)絡(luò)的構(gòu)建和虛擬機的配置\h2.2.2DNS服務(wù)器的搭建\h2.2.3郵件服務(wù)器的建立\h2.3HA集群環(huán)境在虛擬機上的實現(xiàn)\h2.3.1對HAAdd-on的理解\h2.3.2Linux主機的準(zhǔn)備以及虛擬機的構(gòu)建\h2.3.3HAAdd-On的導(dǎo)入和配置\h2.3.4HA集群設(shè)計及運用的準(zhǔn)備\h第3章10輪決勝!在自編的腳本中靈活使用命令\h3.1簡單有效的Shell腳本\h3.2Shell腳本的基本規(guī)則\h3.2.1Shell腳本的操作確認(rèn)\h3.2.2引號的使用方法\h3.2.3條件判斷的寫法\h3.2.4數(shù)組和位置參數(shù)的使用方法\h3.2.5命令置換和數(shù)值演算\h3.3用Shell腳本一決勝負(fù)\h3.3.1[第1輪對決]在跳板服務(wù)器上學(xué)到的秘籍~基本模式+異常處理\h3.3.2[第2輪對決]在分布式Shell上學(xué)到的秘籍~基本模式+管道\h3.3.3[第3輪對決]在進(jìn)程監(jiān)視中學(xué)到的秘籍~狀態(tài)遷移處理\h3.3.4[第4輪對決]秘籍外傳~由make命令進(jìn)行簡單的批處理\h3.3.5[第5輪對決]從模擬快照(snapshot)學(xué)到的秘籍~用管道操作日志\h3.3.6[第6輪對決]在云備份中學(xué)到的秘籍~在思考實驗中組合處理流程\h3.4Perl腳本的對決\h3.4.1[第7輪對決]自己編寫Perl的樂趣\h3.4.2[第8輪對決]通過Tweet體驗Perl帶來的便利\h3.4.3[第9輪對決]用進(jìn)程監(jiān)控掌握fork\h3.4.4[第10輪對決]終極秘籍Perl與管道的結(jié)合\h第4章最后的堡壘!內(nèi)核源代碼的閱讀\h4.1閱讀源代碼\h4.2內(nèi)核源代碼的走讀方法\h4.2.1Linux內(nèi)核的構(gòu)建步驟\h4.2.2內(nèi)核源代碼探索入門\h4.2.3讀懂結(jié)構(gòu)體和指針\h4.3探索核心子系統(tǒng)\h4.3.1進(jìn)程管理子系統(tǒng)\h4.3.2內(nèi)存管理子系統(tǒng)\h4.4內(nèi)核源代碼的分析實例\h4.4.1Linux內(nèi)核的系統(tǒng)時間\h4.4.2閏秒發(fā)生的瞬間\h4.4.3進(jìn)一步探索的指南\h第5章先行一步!RHEL6新功能綜述\h5.1支持商品化硬件的“操作系統(tǒng)進(jìn)化”\h5.1.1ext4文件系統(tǒng)的采用\h5.1.2NetworkManager服務(wù)的引入\h5.1.3用dracut創(chuàng)建初始RAM磁盤\h5.1.4通過anacron實現(xiàn)定期任務(wù)執(zhí)行\(zhòng)h5.2對服務(wù)器啟動處理進(jìn)行變革的Upstart\h5.2.1Upstart的概要\h5.2.2Upstart任務(wù)的創(chuàng)建示例\h5.3用ControlGroups控制資源分配\h5.3.1ControlGroup的概要\h5.3.2各子系統(tǒng)的主要參數(shù)\h5.3.3cg命令群的管理\h5.3.4虛擬機的cgroups操作\h5.4通過LXC體驗容器型虛擬化技術(shù)\h5.4.1容器型虛擬化技術(shù)的概要\h5.4.2容器中Web服務(wù)器的啟動\h5.4.3其他的容器設(shè)置第1章你必須知道的!Linux內(nèi)部結(jié)構(gòu)1.1Linux的三大基礎(chǔ):磁盤、進(jìn)程、內(nèi)存Linux工程師的工作有時需要登錄陌生的Linux服務(wù)器才能進(jìn)行。在這種時候,起初筆者會用到df、ps和free這三個命令,倒并非出于刻意,只是本能地去執(zhí)行這些指令。例如,當(dāng)你接到一個緊急事件的請求響應(yīng),而事先又不知道該服務(wù)器的配置信息時,就得首先用這三個命令檢查一下這臺服務(wù)器的狀態(tài),并對當(dāng)前資源的使用情況進(jìn)行確認(rèn)。11此外,通過w命令來確認(rèn)是否有用戶在同一時間在同一臺服務(wù)器上工作,也是非常重要的。首先,df命令主要用來檢查文件系統(tǒng)上的可用空間。雖然服務(wù)器在運行過程中通常會對文件系統(tǒng)的使用率進(jìn)行監(jiān)測,但在進(jìn)行設(shè)備維護(hù)而暫時停止監(jiān)測時,就很容易導(dǎo)致意外情況的發(fā)生。比如曾發(fā)生過這樣的嚴(yán)重狀況:當(dāng)被告知“某個命令無法順利執(zhí)行”時,試著輸入df指令,竟發(fā)現(xiàn)此時根文件系統(tǒng)的利用率已高達(dá)100%。因此,在登錄服務(wù)器進(jìn)行工作時,還是養(yǎng)成時常用df命令來檢查文件系統(tǒng)使用率的習(xí)慣吧。df命令也可用于確認(rèn)磁盤分區(qū)的構(gòu)成以及數(shù)據(jù)的分配狀況,還可以確認(rèn)用于保存數(shù)據(jù)的文件系統(tǒng)有多少千兆字節(jié),或是否有NFS安裝區(qū)域等。了解應(yīng)用系統(tǒng)的使用數(shù)據(jù)是如何被組織和存儲的,是全面了解服務(wù)器運行的一個關(guān)鍵。經(jīng)典的軟件開發(fā)著作《人月神話》[1]中寫道:“光看流程圖不看數(shù)據(jù)表只是徒勞,但看了數(shù)據(jù)表,流程圖便不看也罷?!盜T,顧名思義,是指信息技術(shù),其核心自然是信息(數(shù)據(jù))的處理,因此數(shù)據(jù)可以說是所有操作的基本了。此外,服務(wù)器是利用進(jìn)程來處理數(shù)據(jù)的,而ps命令則可以被用來確認(rèn)當(dāng)前服務(wù)器上運行進(jìn)程的狀態(tài)。如果平常我們能接觸到各種ps命令的輸出,那么只需看看進(jìn)程的名稱,就可以大致了解這臺服務(wù)器的用途和設(shè)置。有時會發(fā)現(xiàn)一些意料之外的進(jìn)程正在運行,而經(jīng)過仔細(xì)確認(rèn),可能就會在不經(jīng)意間找到問題的原因。最后的free命令適用于確認(rèn)存儲的使用狀況。通過ps命令所得到的進(jìn)程的信息,再結(jié)合磁盤、高速緩存和內(nèi)存的使用情況,能很好地掌握服務(wù)器的運行狀態(tài),了解這是一個“重載”到什么程度的服務(wù)器。TechnicalNotes[1]《人月神話》弗雷德里克·布魯克斯(著),汪穎(譯),清華大學(xué)出版社,2007所謂的“重載”“輕載”,是一種含糊的說法,實際上是結(jié)合過去CPU的使用率和磁盤I/O的頻率來進(jìn)行綜合判斷的。然而,CPU或I/O操作與內(nèi)存的使用情況是密切相關(guān)的。如同醫(yī)生可以從患者的外部情況推斷病情一樣,通過內(nèi)存的使用情況,就能推斷出包括CPU和I/O在內(nèi)的整個服務(wù)器的運行狀態(tài)。即便在CPU的使用率和磁盤I/O的頻率的歷史數(shù)據(jù)十分翔實的情況下,也應(yīng)時刻質(zhì)疑“莫非是CPU使用率太高了?”“也許是I/O負(fù)載太高了?”,以這樣的態(tài)度去觀察數(shù)據(jù),方能分析出最接近真實狀況的結(jié)果。雖然這個引言稍嫌冗長,但通過以上例子,可以總結(jié)出三個應(yīng)了解的Linux的基本分支,即用于保存數(shù)據(jù)的磁盤、實際處理數(shù)據(jù)的進(jìn)程,以及存儲服務(wù)器的各種運行信息的內(nèi)存。針對以上三點,本章將從Linux內(nèi)部結(jié)構(gòu)的角度出發(fā),介紹有助于實踐應(yīng)用的知識。1.2磁盤和文件1.2.1磁盤的3D參數(shù)Linux這一類操作系統(tǒng)的任務(wù)是隱藏物理硬件信息,即對用戶和上層應(yīng)用屏蔽底層硬件的差異,并提供統(tǒng)一的操作方法。但是,對于磁盤裝置,還是需要讓人知道它的物理構(gòu)造的。這一點似乎常常被誤導(dǎo)。例如,在筆者的RedHatEnterpriseLinux6(RHEL6)測試機上運行fdisk指令,就能得到如下結(jié)果。#fdisk-l/dev/sda
磁盤/dev/sda:500.1GB,500107862016字節(jié)
磁頭255,扇區(qū)63,柱面60801
Units=柱面數(shù)of16065*512=8225280字節(jié)
扇區(qū)大小(邏輯/物理):512字節(jié)/512字節(jié)
I/Osize(minimum/optimal):512bytes/512bytes
磁盤標(biāo)識符:0x8c403069
設(shè)備啟動始點終點塊Id系統(tǒng)
/dev/sda1*16451200083Linux
第1分區(qū)沒有在柱面邊界結(jié)束。
/dev/sda2645105740960000083Linux
/dev/sda35105751318209715282Linux交換/Solaris
/dev/sda4513186080276176407+83Linux
屏幕上出現(xiàn)了警告信息:“第1分區(qū)沒有在柱面邊界結(jié)束”。于是在Web上檢索“磁盤的柱面”,即得到圖1.1這樣的說明圖。圖1.1典型的硬盤的說明圖結(jié)合之前輸出結(jié)果的第2行信息“磁頭255,扇區(qū)63,柱面60801”,此圖該如何解釋呢?那就是,這臺測試機器的硬盤“有255個磁頭數(shù),每個磁道有63個扇區(qū),一個磁盤可以分割出60801個磁道”。當(dāng)然,物理上擁有255個磁頭的磁盤驅(qū)動器是不存在的。磁盤裝置的柱面數(shù)(cylinder)、磁頭(head)、扇區(qū)(sector)信息,三者統(tǒng)稱為CHS或“3D參數(shù)”,然而實際上,fdisk命令表示的3D參數(shù)信息和磁盤裝置的實際構(gòu)造并沒有什么直接的關(guān)系。要弄清楚這是為什么,就需要理解硬盤的兩種不同類型(CHS方式和LBA方式)的存取方法(也經(jīng)常被說成“尋址模式”)以及它們之間的差異。正如圖1.1中所示,要特別規(guī)定數(shù)據(jù)讀取和寫入的扇區(qū)(物理磁盤存取的最小單位)所處的位置,只需指定以下三個數(shù)值即可:柱面數(shù)(從最外緣開始計算第幾條磁道)、磁頭數(shù)(磁盤表面的讀/寫頭的個數(shù))以及扇區(qū)數(shù)(磁道內(nèi)等分弧段的個數(shù))。使用時間超過10年的舊式磁盤中,磁盤裝置的這三個值(CHS值)指明了讀寫數(shù)據(jù)的位置,這就是CHS方式。但實際上,Linux設(shè)備驅(qū)動程序會計算CHS值,以進(jìn)行磁盤裝置與數(shù)據(jù)之間的讀寫,因此用戶是不需要知道它們的具體數(shù)值的。在磁盤仍然使用CHS方式的時代,唯一一次需要用戶在操作時知道CHS值的,是在創(chuàng)建磁盤分區(qū)的時候。根據(jù)當(dāng)時的MS-DOS方式,磁盤分區(qū)必須以扇區(qū)為單位進(jìn)行操作。由于柱面是從磁盤的外緣開始按順序進(jìn)行編號的,因而磁盤柱面的分割與編號大致如圖1.2所示。過去還曾有人異想天開,想在不同的物理磁盤(磁盤面)上采用不同的分割方式,但遺憾的是,這樣的分區(qū)方式是無法實現(xiàn)的。圖1.2典型的分區(qū)的分割方法雖然Linux沒有必要遵循MS-DOS方式,但在當(dāng)時,通過將操作系統(tǒng)引入不同的分區(qū),可以實現(xiàn)MS-DOS和Linux的多重引導(dǎo)或是Windows和Linux的多重引導(dǎo)。因此,和MS-DOS或Windows遵循共同的方式是有實際意義的。如此一來,和MS-DOS中的fdisk.exe一樣,Linux中的fdisk命令在做磁盤分區(qū)時,也得用柱面數(shù)來指定分區(qū)的開始位置和結(jié)束位置了。然而,這種有著悠久歷史的舊式硬盤早已被時代淘汰,淪為“計算機歷史博物館”中的陳列品了(這種說法可能有些夸張,但至少在筆者的家中是難覓其蹤了)?,F(xiàn)在的硬盤普遍采用LBA(LogicBlockAddressing,邏輯塊尋址)方式進(jìn)行數(shù)據(jù)存取。這種方式的機制極其簡單,即硬盤內(nèi)所有的扇區(qū)均從0開始進(jìn)行編號(扇區(qū)編號),通過扇區(qū)數(shù)來指定扇區(qū)的位置。扇區(qū)號與物理扇區(qū)位置之間的對應(yīng),是由內(nèi)置的硬盤控制器來計算的。通常來說,扇區(qū)號越小,其對應(yīng)的物理扇區(qū)就越位于磁盤的外側(cè)。與此相結(jié)合,分區(qū)的開始位置和結(jié)束位置同樣也是由扇區(qū)號來指定的。之前的fdisk命令的輸出中,是按照傳統(tǒng)的CHS方式,使用柱面號來表示各分區(qū)的起點和終點的,但實際上這并不是真實的信息。真正的分區(qū)信息,需要在fdisk命令之后加上選項-u來獲取。#fdisk-lu/dev/sda
磁盤/dev/sda:500.1GB,500107862016字節(jié)
磁頭255,扇區(qū)63,柱面60801,合計976773168扇區(qū)
Units=扇區(qū)數(shù)of1*512=512字節(jié)
扇區(qū)大小(邏輯/物理):512字節(jié)/512字節(jié)
I/Osize(minimum/optimal):512bytes/512bytes
磁盤標(biāo)識符:0x8c403069
設(shè)備啟動始點終點塊Id系統(tǒng)
/dev/sda1*2048102604751200083Linux
第1分區(qū)沒有在柱面邊界結(jié)束。
/dev/sda2102604882022604740960000083Linux
/dev/sda3820226048824420351209715282Linux交換/Solaris
/dev/sda482442035297677316676176407+83Linux
如圖所示,各個分區(qū)的起點和終點是由扇區(qū)號來表示的。這些扇區(qū)號所劃分出的范圍就是實際的分區(qū)。圖中第一個分區(qū)是從2048號扇區(qū)開始的,由此可知0~2047扇區(qū)是保留扇區(qū),它們不被用作分區(qū)。磁盤的開始部分為主引導(dǎo)扇區(qū)MBR,GRUBstage1.5就保存在MBR之后的空間中。這里的情形是,第0號扇區(qū)為主引導(dǎo)扇區(qū),stage1.5則存儲在主引導(dǎo)扇區(qū)后直至第2047號扇區(qū)之間的空間中2。2第1分區(qū)的起始位置,以前的標(biāo)準(zhǔn)是第63扇區(qū),最近變更為第2048扇區(qū)。而stage1.5并沒有那么大,因此在之前的起始位置保存stage1.5也沒有問題。繞了這么大一個圈,下面就開始解釋上文所提到的警告信息吧。由于現(xiàn)在的硬盤是以LBA方式存取的,因此分區(qū)的開始和結(jié)束位置皆通過扇區(qū)號來指定。雖然這樣做一點問題都沒有,但是fdisk命令為了支持舊式CHS方式的磁盤,仍然以CHS方式來表示磁盤信息。這時,對于LBA方式的磁盤,需要轉(zhuǎn)換成其對應(yīng)的3D(磁頭數(shù)、扇區(qū)數(shù)、柱面數(shù))參數(shù)。當(dāng)分區(qū)的結(jié)束位置不能用3D參數(shù)中合適的柱面結(jié)束位置來對應(yīng)表示時,就會出現(xiàn)諸如“第1分區(qū)沒有在柱面邊界結(jié)束”這樣的警告信息??傊?,這種警告信息的出現(xiàn),意味著“操作系統(tǒng)正以柱面為單位對磁盤進(jìn)行分區(qū),可能會導(dǎo)致一些問題”。不過對于在Linux下使用的磁盤,這種顧慮是多余的?,F(xiàn)在,在fdisk命令之后加上選項-u,便可以通過指定扇區(qū)號來指定分區(qū)。因此,今后還是養(yǎng)成在fdisk命令后附加選項-u的習(xí)慣吧3。3在RedHatEnterpriseLinux的高級開發(fā)版本Fedora所包含的fdisk命令中,默認(rèn)的操作是以扇區(qū)為單位的。當(dāng)需要進(jìn)行舊式的以柱面為單位的操作時,需要指定選項-u=cylinders。1.2.2新舊分區(qū)表前一節(jié)介紹的表示分區(qū)開始和結(jié)束位置的信息,它們究竟會被寫入到磁盤的哪里呢?這是一個常常被問到的問題,答案毫無疑問是“分區(qū)表”。準(zhǔn)確地說,分區(qū)表就是存放在第0號扇區(qū)MBR的446~509字節(jié)的部分。在MBR的0~445字節(jié)中,存放的是所謂的引導(dǎo)加載程序,即服務(wù)器啟動時,用于引導(dǎo)BIOS的加電自檢以及GRUBstage1的加載。由于一個扇區(qū)的大小是512字節(jié),這里就會有510~511(從0字節(jié)開始,到511字節(jié)結(jié)束)兩個字節(jié)的剩余,于是按慣例這里的數(shù)值就記錄為0xAA55。若磁盤此處的值不為0xAA55,則判斷該磁盤的MBR已損壞。由于分區(qū)表的大小只有64個字節(jié),因此大部分信息不能被寫入其中。在每個分區(qū)表中,只記錄著“用CHS方式描述的分區(qū)開始位置和結(jié)束位置”以及“用LBA方式(扇區(qū)號)描述的分區(qū)開始位置以及包含的扇區(qū)數(shù)”這類有代表性的信息(結(jié)束位置不用扇區(qū)號來記錄,而是通過開始位置與扇區(qū)數(shù)相加計算得到)。之所以要通過兩種方式記錄分區(qū)開始和結(jié)束位置的信息,是有其歷史原因的。LBA方式的磁盤實際上是不使用CHS方式記錄分區(qū)信息的。圖1.3是通過hexdump命令輸出的MBR第446字節(jié)開始往后66字節(jié)的內(nèi)容(分區(qū)表加最后兩個字節(jié))。通過設(shè)置詳細(xì)的選項,輸出了以十進(jìn)制形式表示的LBA方式的分區(qū)信息。圖1.3分區(qū)表的轉(zhuǎn)儲輸出方框里的4行數(shù)據(jù),分別是4個分區(qū)的信息。將它與之前帶選項-u的fdisk命令的輸出相比較,可以確定采用LBA方式記錄的扇區(qū)號的信息與之前的信息是一致的。CHS方式描述的數(shù)值在此不做詳細(xì)分析,但從分區(qū)的開始位置和結(jié)束位置出現(xiàn)了若干個相同的數(shù)值可以看出,這是段沒有意義的信息。由于CHS方式描述的信息實際上并不會被投入使用,因此問題不大,但還是應(yīng)當(dāng)注意避免混淆。順帶一提,最后兩個字節(jié)正是前面介紹的0xAA55,而把圖1.3的最后看成0x55AA的讀者,還請自行學(xué)習(xí)一下“小端”(littleendian)的知識。如此看來,使用LBA方式是最為簡單便捷的了。不過,近來這種方式也出現(xiàn)了它的局限性。那么是什么呢?如圖1.3所示,雖然采用十進(jìn)制比較難懂,但能看出表示開始位置的扇區(qū)號和全體扇區(qū)數(shù)的數(shù)字總共是4個字節(jié),因此可以表示的范圍僅為0x00000000~0xFFFFFFFF。換句話說,它無法支持扇區(qū)數(shù)超過0xFFFFFFFF的大容量磁盤??梢韵胂蟪鲞@個容量是多大嗎?我們知道一個扇區(qū)是512個字節(jié),用十六進(jìn)制的計算器進(jìn)行計算,答案應(yīng)該是2TB。也許有人要問,如果沒有十六進(jìn)制的計算器該怎么辦?即便沒有這樣的計算器,也可以在Linux上通過使用bc指令來計算,如下所示。ibase=16即指定“輸入值為十六進(jìn)制”。另外這里提醒大家一下,0xFF表示的是十進(jìn)制數(shù)256。#echo"ibase=16;FFFFFFFF*FF*2"|bc
2190433320450
因此,MBR中的分區(qū)表是有限度的,對于容量大于2TB的硬盤,是無法為之創(chuàng)建分區(qū)的。當(dāng)使用外部存儲裝置LUN(邏輯磁盤)作為數(shù)據(jù)存儲區(qū)域時,則無需對LUN進(jìn)行分區(qū),只需將其格式化后掛載到文件系統(tǒng)中,或使用LVM(邏輯卷管理)方法將其作為邏輯卷進(jìn)行管理等。這樣,容量大于2TB的LUN就也能夠使用了。不過,近來的服務(wù)器磁盤正逐步趨向大容量化,隨著容量大于2TB的本地磁盤的普及,找到容量大于2TB的磁盤的分區(qū)方法也指日可待。GPT(GUIDPartitionTable,GUID分區(qū)表)正是為了解決這個問題應(yīng)運而生的。現(xiàn)在,如果需要從使用GPT的硬盤中啟動操作系統(tǒng),就需要服務(wù)器和操作系統(tǒng)都能支持UEFI。操作系統(tǒng)中,目前的RedHatEnterpriseLinux6(RHEL6)是能支持UEFI的。此外,雖然與分區(qū)表并不直接相關(guān),但在最近的大容量磁盤中,有的已經(jīng)以4KB作為一個扇區(qū)的大小了。接下來就對UEFI和GPT,以及4KB扇區(qū)的磁盤做一個詳細(xì)的介紹,內(nèi)容或許略微復(fù)雜,請大家認(rèn)真學(xué)習(xí)。UEFI和GPTUEFI是以后將要取代BIOS的一個方案。我們都知道,當(dāng)服務(wù)器接上電源,系統(tǒng)BIOS就開始啟動。BIOS的啟動只允許使用1M的內(nèi)存空間。因此系統(tǒng)BIOS的設(shè)置界面不是圖形界面,而是非常簡單的基于文本形式的界面。而且服務(wù)器上搭載的各種設(shè)備的設(shè)置不是通過BIOS的設(shè)置界面來操作的,而是需要通過Ctrl+A等按鍵來單獨操作設(shè)置界面。這些都是因為BIOS所能使用的內(nèi)存空間有限。UEFI打破了BIOS的這些限制,在功能方面進(jìn)行了多種擴展,于是支持UEFI的服務(wù)器在啟動時,就可以直接通過UEFI的設(shè)置界面來調(diào)用各種設(shè)備,有的服務(wù)器甚至已經(jīng)有了圖形化的設(shè)置界面。此外,調(diào)用引導(dǎo)加載程序的方法也發(fā)生了改變。以前都需要像GRUBstage1、stage1.5、stage2這樣分階段啟動引導(dǎo)加載程序,而改進(jìn)后,在以GPT方式創(chuàng)建的“EFI系統(tǒng)分區(qū)”中,引導(dǎo)加載程序存儲就可以直接被調(diào)用了。最后介紹一下GPT。過去的分區(qū)表在第0扇區(qū)MBR里,GPT則被寫入第1扇區(qū)至第33扇區(qū)中,成為一種新型的分區(qū)表(圖1.4)。表1.1中總結(jié)了這兩種分區(qū)方式的主要區(qū)別。圖1.4GPT的構(gòu)造表1.1以前的分區(qū)和GPT的比較
以前的分區(qū)GPT分區(qū)表的位置MBRMBR之后(磁盤末尾亦有副本)最大磁盤容量2TB8ZB(無限)最大分區(qū)數(shù)15(使用SCSI磁盤時)1284分區(qū)卷標(biāo)分區(qū)ID(表示用途的ID)GUID(表示用途的ID+唯一的ID)制作分區(qū)的工具fdiskparted4在設(shè)計GPT時,通過改變GPT頭的設(shè)置,也可以創(chuàng)建出超過128個分區(qū)。但一般情況下,128個仍是最大限度。為了降低分區(qū)表損壞的風(fēng)險,GPT在硬盤的最后保存了一份同樣內(nèi)容的分區(qū)表副本。GPT的頭部,則記錄了可以用作分區(qū)的扇區(qū)范圍。每個分區(qū)的信息都記錄在“分區(qū)表”中。一個分區(qū)表是128字節(jié),一個扇區(qū)(512字節(jié))可以記錄4個分區(qū)的信息。每個分區(qū)的開始扇區(qū)和結(jié)束扇區(qū)都分別用8個字節(jié)來記錄,因此即便是容量大于2TB的硬盤的扇區(qū)數(shù),處理起來也是綽綽有余的。每個分區(qū)中都記錄著一個特定的GUID標(biāo)簽。尤其是用來存儲引導(dǎo)裝載程序的分區(qū),會附上“EFI系統(tǒng)分區(qū)”(ESP)的標(biāo)簽。如果是RHEL6,/boot/efi下掛載的文件系統(tǒng)就是ESP類型的分區(qū)。這里保存了類似于GRUBstage2(grub.efi)的啟動過程。支持UEFI的服務(wù)器,會根據(jù)GUID定位ESP,啟動其中的grub.efi5,因此就不再需要GRUBstage1和stage1.5了。ESP采用的是VFAT格式。當(dāng)創(chuàng)建一個GPT格式的分區(qū)時,應(yīng)使用parted命令。表1.2描述了parted命令的主要內(nèi)部命令,它們的具體使用方法可以在網(wǎng)上查到,此處不再贅述。表1.2parted命令的主要內(nèi)部命令
命令說明check對文件系統(tǒng)進(jìn)行檢查cp復(fù)制分區(qū)help顯示對相關(guān)命令的說明?!癶elp命令名稱>”可以顯示每一條命令的詳細(xì)信息命令名稱>mkfs創(chuàng)建文件系統(tǒng)mklabel指定表示分區(qū)表類型的磁盤標(biāo)簽。在使用GPT時即指定“gpt”mkpart創(chuàng)建分區(qū)mkpartfs進(jìn)行分區(qū)和文件系統(tǒng)的創(chuàng)建move移動分區(qū)print顯示當(dāng)前的分區(qū)表或磁盤標(biāo)簽的狀態(tài)quit結(jié)束parted命令resize改變分區(qū)的大firm刪除分區(qū)select指定要處理的設(shè)備(例如:/dev/sda)set設(shè)置包括引導(dǎo)標(biāo)志在內(nèi)的各種標(biāo)志由于RHEL6也支持GPT,因此在容量大于2TB的硬盤上進(jìn)行安裝時,會自動采用GPT方式進(jìn)行分區(qū)。TechnicalNotes[2]使用RHEL6Rescue模式的備份指南(非LVM環(huán)境/NFS環(huán)境/uEFI模式版)\h/jp/linux/tech/doc/attachments/003bc366_rhel6-rescuee383a2e383bce38389e38292e4bdbfe794a8e38197e_12.pdf64KB扇區(qū)的磁盤以前的傳統(tǒng)硬盤,一個扇區(qū)固定為512字節(jié)。而對于大容量硬盤,則通過增加扇區(qū)的大小,來減小訪問扇區(qū)產(chǎn)生的消耗。另外,硬盤內(nèi)部記錄了每個扇區(qū)錯誤校驗所需要的信息。通過增加扇區(qū)的大小,可以降低這些附加信息所占的百分比,使記錄數(shù)據(jù)的空間得到更加有效的利用。但是,由于訪問硬盤的服務(wù)器硬件或操作系統(tǒng)(設(shè)備驅(qū)動)都是按照之前512字節(jié)的扇區(qū)大小設(shè)計的,因此不能一味單純地增加硬盤扇區(qū)的大小。為了實現(xiàn)兩者的兼容,就產(chǎn)生了通過硬盤中的控制器來從邏輯上模擬512字節(jié)扇區(qū)的運作方式。如圖1.5所示,從服務(wù)器的角度來看,扇區(qū)的大小仍然是512字節(jié),但實際的數(shù)據(jù)讀取和寫入是在4KB扇區(qū)上進(jìn)行的。最近有不少新面世的硬盤均采用了這種處理方式。圖1.54KB扇區(qū)的磁盤結(jié)構(gòu)乍一看,這種轉(zhuǎn)換方式會產(chǎn)生一定的開銷。在讀取4KB扇區(qū)中的邏輯扇區(qū)數(shù)據(jù)時,即便僅僅512個字節(jié)的讀取和寫入,也會需要對整個4KB扇區(qū)進(jìn)行操作。但是實際上,若是大數(shù)據(jù)的讀取和寫入是從4KB扇區(qū)的起始位置開始的,則基本上并不會產(chǎn)生額外的開銷。要有效地實現(xiàn)這樣的效果,不僅需要將分區(qū)的開始位置與4KB扇區(qū)的起始邊界對齊,還需要將文件系統(tǒng)的塊大小調(diào)整為4KB(4096字節(jié))(關(guān)于文件系統(tǒng)的塊大小,將在下一節(jié)中進(jìn)行詳細(xì)介紹)。在筆者之前介紹的測試機的例子中,第一個分區(qū)/dev/sda1是從第2048扇區(qū)開始的。如果將其轉(zhuǎn)換成圖1.5的邏輯區(qū)段數(shù),就恰好和第256個4KB扇區(qū)的起始邊界對齊。因為分區(qū)中包含的扇區(qū)數(shù)也是8的倍數(shù),因此分區(qū)的結(jié)束位置也就正好是4KB扇區(qū)的結(jié)束邊界。/dev/sda2和/dev/sda3也是如此,這些分區(qū)是在RHEL6的安裝界面中設(shè)置的??梢姲惭b程序很嚴(yán)謹(jǐn)?shù)乜紤]到了這些問題。當(dāng)然,這些都是僅在使用4KB扇區(qū)的硬盤時才需要注意的事項,但將來一定會有越來越多的硬盤采用4KB扇區(qū)。因此,在設(shè)置分區(qū)的開始位置以及大小時,將邏輯扇區(qū)數(shù)設(shè)置為8的倍數(shù)是比較好的7,這種方法被稱為“分區(qū)對齊”。在用parted命令創(chuàng)建GPT分區(qū)時,默認(rèn)情況下會指定分區(qū)的開始位置、結(jié)束位置和容量(例如MB)。此時,parted命令會自動對齊所創(chuàng)建的分區(qū)。如果不放心的話,可以通過“units”命令來指定扇區(qū),對分區(qū)的開始和結(jié)束位置進(jìn)行確認(rèn)。5恢復(fù)系統(tǒng)備份后,有時候需要通過UEFI的設(shè)置界面重新設(shè)置啟動對象的啟動加載文件。點擊[2]的鏈接可以看到使用IBMSystemx時的操作順序。6此處為日文資料。——譯者注74KB扇區(qū)的磁盤中有一個被稱為“對齊偏移”的功能,在該功能有效的情況下,需要將分區(qū)的起始位置設(shè)為“8的倍數(shù)+7”。由于這是Linux中不需要的功能,因此在能夠通過硬盤的跳線開關(guān)等進(jìn)行更改的情況下,建議禁用該功能。詳情請參考[3]。1.2.3文件系統(tǒng)和I/O子系統(tǒng)文件系統(tǒng)的塊大小我們先來重新思考一下文件系統(tǒng)的數(shù)據(jù)訪問。說到文件系統(tǒng),大家可能會想到ext3、ext4等,但在本節(jié),筆者打算從更為宏觀的角度來介紹文件系統(tǒng)。首先,Linux中,有將各種不同的文件系統(tǒng)統(tǒng)一起來的VFS(VirtualFileSystem,虛擬文件系統(tǒng))層,還有通過設(shè)備驅(qū)動將數(shù)據(jù)讀取或?qū)懭胛锢泶疟P的塊層,它們一起組成了圖1.6中所示的I/O子系統(tǒng)。Linux的文件系統(tǒng)只是VFS層中的一部分。圖1.6I/O子系統(tǒng)的結(jié)構(gòu)TechnicalNotes[3]LinuxKernelWatch:超過2TB!ATA磁盤的4KB扇區(qū)問題是什么?\hhttp://www.atmarkit.co.jp/flinux/rensai/watch2010/watch03a.html8前文提到的“文件系統(tǒng)的塊大小”,是塊層中的設(shè)備驅(qū)動程序?qū)?shù)據(jù)讀取或?qū)懭胛锢泶疟P的最小單位。從物理磁盤的結(jié)構(gòu)上看,是以512字節(jié)的扇區(qū)單位來讀取和寫入數(shù)據(jù)的,但很多時候采用較大的單位來讀取和寫入數(shù)據(jù)可以更有效地進(jìn)行數(shù)據(jù)交換,而指定這種單位的就是塊大小。在Linux中,文件系統(tǒng)的塊大小有1024字節(jié)、2048字節(jié)和4096字節(jié)這幾種選項。默認(rèn)的塊大小被記錄在配置文件/etc/mke2fs.conf中,也可以通過mke2fs命令的-b參數(shù)來明確指定塊大小。若要對已經(jīng)創(chuàng)建好的文件系統(tǒng)所設(shè)置的塊大小進(jìn)行確認(rèn),則應(yīng)使用tune2fs命令9。我們在上一節(jié)中提到,在4KB扇區(qū)磁盤的情況下,應(yīng)使分區(qū)的開始位置與4KB扇區(qū)的起始邊界相對齊,并將文件系統(tǒng)的塊大小也設(shè)置為4KB(4096字節(jié))。圖1.7給出了這樣做的原因。圖1.7中,上圖表示了滿足這種條件的情況,設(shè)備驅(qū)動程序?qū)ξ锢泶疟P的訪問實際上只對應(yīng)了一個4KB扇區(qū),沒有產(chǎn)生無效的數(shù)據(jù)讀寫。圖1.74KB扇區(qū)和塊大小的映射下圖則表示了分區(qū)的開始位置與4KB扇區(qū)的起始邊界沒有對齊的情況。打個比方,假使設(shè)備驅(qū)動程序?qū)懭肓艘粋€塊。由于物理磁盤不能只對4KB扇區(qū)的一部分進(jìn)行重寫,因此需要先讀取出兩個扇區(qū)的數(shù)據(jù),按要求對其中的部分?jǐn)?shù)據(jù)進(jìn)行重寫,然后再將處理后的數(shù)據(jù)重新寫入這兩個扇區(qū)。這顯然會造成額外的開銷。鏈接[4]里比較了分區(qū)的開始位置與4KB扇區(qū)的起始邊界對齊和不對齊的情況下分別對磁盤訪問性能造成的影響。據(jù)分析,分區(qū)開始位置發(fā)生偏離時,磁盤的數(shù)據(jù)寫入性能會出現(xiàn)顯著的下降。順便說一下,類似的情形在常見的512字節(jié)扇區(qū)的磁盤中也會發(fā)生,當(dāng)分區(qū)的大小不為塊大小的整數(shù)倍時,最終會有一個塊超出分區(qū)。這種情況下,最終的這個塊就不會在文件系統(tǒng)中使用。圖1.8即為塊大小為2048字節(jié)的一個例子,這時分區(qū)剩下的最后兩個扇區(qū)就不會被使用。TechnicalNotes[4]4KB扇區(qū)磁盤上的Linux:實際建議\h/developerworks/cn/linux/l-4kb-sector-disks/圖1.8最后的塊超出分區(qū)的情況還是題外話,在fdisk命令的輸出中,有時塊數(shù)的值后面可以看到附加的+記號。比如“1.2.1磁盤的3D參數(shù)”一例中,/dev/sda4的塊數(shù)(分區(qū)中包含的扇區(qū)數(shù))后就有+記號。當(dāng)塊數(shù)為奇數(shù)值時,便會附加上這個符號。這是有其歷史原因的。過去的Linux文件系統(tǒng)的塊大小規(guī)定為1024字節(jié),因此當(dāng)分區(qū)中的扇區(qū)數(shù)為奇數(shù)值時,就會剩下最后的扇區(qū)不被使用。+記號就是為了表示“該分區(qū)最后一個扇區(qū)不會被使用”而特意附上的,但現(xiàn)在這也許是多余的了。I/O子系統(tǒng)的概貌我們來回顧一下圖1.6中介紹的I/O子系統(tǒng)的整體結(jié)構(gòu),分別從寫入數(shù)據(jù)和讀取數(shù)據(jù)兩種情況進(jìn)行考慮。首先來看看寫入數(shù)據(jù)的情形。當(dāng)數(shù)據(jù)被寫入文件系統(tǒng)的文件中時,其內(nèi)容會被暫時錄入到磁盤高速緩存中(①)。這時發(fā)出寫入數(shù)據(jù)命令的應(yīng)用程序(用戶進(jìn)程)會將此步驟視為數(shù)據(jù)已錄入成功,從而進(jìn)行下一步操作。然而此時就會有些數(shù)據(jù)只是被寫入到了磁盤高速緩存中,而沒有被寫入到物理磁盤中去。這種數(shù)據(jù)稱為“臟數(shù)據(jù)”。當(dāng)磁盤高速緩存上的臟數(shù)據(jù)積累到一定程度時,文件系統(tǒng)便會向I/O調(diào)度發(fā)出請求,將這些臟數(shù)據(jù)寫入物理磁盤(②)。這個寫入請求將被添加到I/O調(diào)度內(nèi)部的“請求隊列”中。最后,I/O調(diào)度器會響應(yīng)請求隊列中的請求,利用設(shè)備驅(qū)動程序?qū)?shù)據(jù)寫入物理磁盤中(③④)。大家可能聽說過多種類型的I/O調(diào)度器,例如cfq、deadline等。它們之間的差別在于使用的算法不同,即按何種順序處理請求隊列中的請求才最高效。關(guān)于I/O調(diào)度器,之后會做更加詳細(xì)的說明。此外,表1.3中列出的內(nèi)核參數(shù),能夠用于調(diào)整臟數(shù)據(jù)寫入的頻率。不過除非有特別的原因,否則是不需要更改默認(rèn)值的。表1.3與數(shù)據(jù)的寫出頻率相關(guān)的內(nèi)核參數(shù)
內(nèi)核參數(shù)說明vm.dirty_background_radio
vm.dirty_radio試圖將緩存中臟數(shù)據(jù)的百分比保持在“dirty_background_radio(%)”之下。尤其是當(dāng)臟數(shù)據(jù)的百分比超過“dirty_radio(%)”時,將立即增加寫出頻率vm.dirty_background_bytes
vm.dirty_bytes以字節(jié)為單位操作與上面相同的指定。優(yōu)先于上面的指定,設(shè)置為0時則保持上面的指定vm.dirty_writeback_centisecs
vm.dirty_expire_centisecs每“dirty_writeback_centisecs(單位為1/100秒)”檢查磁盤緩存,每超過1“dirty_expire_centisecs(單位為1/100秒)”,就持續(xù)寫入新的數(shù)據(jù)至于數(shù)據(jù)的讀取,則是按以下流程進(jìn)行的。假設(shè)應(yīng)用程序(用戶進(jìn)程)要從文件系統(tǒng)的文件中讀出數(shù)據(jù)。如果目標(biāo)數(shù)據(jù)已經(jīng)存在于磁盤的高速緩存中,文件系統(tǒng)便將這些數(shù)據(jù)返回給進(jìn)程,從而完成處理(①)。反之,如果目標(biāo)數(shù)據(jù)不在磁盤的高速緩存中,那么I/O調(diào)度的進(jìn)程會暫停執(zhí)行并進(jìn)入等待狀態(tài),之后該文件系統(tǒng)會向I/O調(diào)度器發(fā)出讀取數(shù)據(jù)的請求(②)。最后,I/O調(diào)度器響應(yīng)請求,通過設(shè)備驅(qū)動程序把數(shù)據(jù)從物理磁盤讀入磁盤高速緩存中(③④),解除I/O調(diào)度進(jìn)程的等待狀態(tài),再接著處理磁盤高速緩存中的數(shù)據(jù)(①)。磁盤高速緩存和文件系統(tǒng)屬于VFS層,I/O調(diào)度和設(shè)備驅(qū)動屬于塊層,二者相互配合來完成文件中數(shù)據(jù)的讀取和寫入。之所以將它們分為兩個不同的層,是基于Linux內(nèi)核中“模塊化結(jié)構(gòu)”的概念。這樣就可以將不同類型的文件系統(tǒng)和不同類型的物理磁盤隨意組合起來使用。再舉個極端的例子,即便是沒有物理磁盤的文件系統(tǒng)也能實現(xiàn)數(shù)據(jù)的處理。例如,ramfs是利用內(nèi)存來提供RAM磁盤功能的文件系統(tǒng),它就完全沒有圖1.6的②(數(shù)據(jù)傳輸請求)這個步驟。那么寫入的數(shù)據(jù)究竟到哪里去了呢?實際上它們都保留在磁盤緩存中。若是一般的文件系統(tǒng),臟數(shù)據(jù)一旦被寫入物理磁盤,就不再是臟數(shù)據(jù),因此需要從磁盤高速緩存中刪除。但ramfs則不同,磁盤高速緩存中的數(shù)據(jù)永遠(yuǎn)是臟數(shù)據(jù),永遠(yuǎn)不會被刪除。ramfs被描述成“基于內(nèi)存的RAM磁盤”,其實準(zhǔn)確來說,應(yīng)該是“基于磁盤高速緩存的RAM磁盤”。在Linux中,還有一個和ramfs具備相同功能的tmpfs。tmpfs同樣是將數(shù)據(jù)保存在磁盤高速緩存中,但有別于ramfs的是,它的內(nèi)容還可以成為“換出”的對象。換句話說,當(dāng)物理內(nèi)存不足時,存儲在tmpfs的文件會被寫入物理磁盤的交換空間中,這樣文件使用的內(nèi)存就可以被釋放。關(guān)于tmpfs這種允許換出的機制,在本章1.4.1節(jié)中也會所介紹??吹竭@里,可能有人會產(chǎn)生這樣的疑問:“ramfs和tmpfs,到底選用哪個好呢?”要是只作一般用途,例如應(yīng)用程序中所使用的數(shù)據(jù)的臨時存儲,建議還是采用tmpfs。這是因為,tmpfs有設(shè)置內(nèi)存使用上限的功能,而ramfs則沒有這樣的功能。如果無限制地往ramfs上保存文件,就會持續(xù)消耗內(nèi)存,而且內(nèi)存部分也不能被換出,最終就會因為內(nèi)存不足而啟動OOMKiller。順帶一提,ramfs的原作者正是Linus先生,在源碼ramfs/inode.c中還能看到Linus先生留下的注釋。*NOTE!Thisfilesystemisprobablymostuseful*notasarealfilesystem,butasanexampleof*howvirtualfilesystemscanbewritten.以上注釋都表明,ramfs只是作為一個最簡單的文件系統(tǒng)的示例而創(chuàng)建出來的,它并不適合實際使用。不過,在Linux內(nèi)核中,有一個地方是使用ramfs的。在Linux的引導(dǎo)過程中,內(nèi)核啟動后,初始RAM磁盤內(nèi)容10會被裝載到RAM磁盤空間中。這里的RAM磁盤空間就需要用到ramfs。理解I/O調(diào)度器我們繼續(xù)回顧圖1.6,看看I/O調(diào)度器是如何處理文件系統(tǒng)的數(shù)據(jù)傳輸請求的。磁盤高速緩存和物理磁盤之間進(jìn)行數(shù)據(jù)傳輸時,磁盤高速緩存中數(shù)據(jù)的存儲方式和物理磁盤中數(shù)據(jù)的存儲方式是不一致的。首先,在磁盤高速緩存上,一個文件中連續(xù)的數(shù)據(jù)基本上會被寫入到連續(xù)的存儲空間中。然而,同樣的數(shù)據(jù)在物理磁盤上就不一定會被放置在連續(xù)的存儲空間中了,這種情況被稱為“磁盤碎片”。如圖1.9所示,磁盤高速緩存中連續(xù)的數(shù)據(jù)被分成了兩個部分,分別被寫入了物理磁盤上兩個連續(xù)的扇區(qū)內(nèi)。在本圖的例子中,文件的開始和結(jié)束部分的內(nèi)容被設(shè)置在了物理磁盤上相鄰的位置。此外,Linux的內(nèi)存以4KB的頁為管理單位,磁盤高速緩存中1個頁能寫入8個扇區(qū)的數(shù)據(jù)。圖1.9磁盤高速緩存和物理磁盤的對應(yīng)示例正如圖例所示,文件系統(tǒng)的作用就是決定如何將文件的數(shù)據(jù)分配在磁盤上,而圖1.9中的對應(yīng)關(guān)系正是記錄在元數(shù)據(jù)區(qū)中的。因此,圖1.6中文件系統(tǒng)向I/O調(diào)度器發(fā)出數(shù)據(jù)傳輸請求時,文件系統(tǒng)就會對物理磁盤上的連續(xù)數(shù)據(jù)進(jìn)行分割處理。如此一來,I/O調(diào)度器就能夠有效地讀取物理磁盤上的連續(xù)數(shù)據(jù)。說得夸張點,即便在考慮性能問題時,對I/O調(diào)度器的理解也是非常重要的,因此這里會對I/O調(diào)度器做盡可能全面的介紹。首先,文件系統(tǒng)會將數(shù)據(jù)分配到物理磁盤上的連續(xù)空間(連續(xù)扇區(qū))中,在內(nèi)核中整合創(chuàng)建出一個bio對象,再把這個bio對象傳遞給I/O調(diào)度器。從圖1.9中可以看出,有兩個bio對象要傳遞給I/O調(diào)度器。I/O調(diào)度器接收到來自文件系統(tǒng)的bio對象,會將多個bio對象合并為一個請求對象,再將它加入到請求隊列中。(圖1.10)圖1.10I/O調(diào)度器的結(jié)構(gòu)請求對象的合并方法因I/O調(diào)度器而異,一般來說,如果bio對象指定的連續(xù)扇區(qū)同時也是請求隊列中已有的請求對象所指定的連續(xù)扇區(qū),那么就會將這兩個對象合并。如果沒有一致的請求對象,則創(chuàng)建一個只包含該bio對象的新的請求對象。最后,物理磁盤空間上的數(shù)據(jù)才會在請求對象所指定的區(qū)域進(jìn)行讀取或?qū)懭?。連續(xù)扇區(qū)上數(shù)據(jù)的讀取和寫入就是這樣一并進(jìn)行的。此外,這些請求對象的實際處理順序也是因I/O調(diào)度器而異的。例如cfq(completefairqueuing)調(diào)度器,其進(jìn)程的bio對象會被加入到不同的子隊列中,以便盡量公平處理每個進(jìn)程的請求。從圖1.10中可以了解子隊列的機制。I/O調(diào)度器接收的bio對象,首先會被作為請求對象加入到子隊列中。子隊列中的請求對象增加到一定程度后,便會按照實際傳輸處理的順序從子隊列轉(zhuǎn)移到調(diào)度隊列中,進(jìn)行實際的數(shù)據(jù)處理?,F(xiàn)在大家應(yīng)該都明白I/O調(diào)度器的機制了吧。接下來對具體的I/O調(diào)度器之間的區(qū)別進(jìn)行介紹。Linux中主要使用的是以下四種I/O調(diào)度器,它們的特征分別如下:noop(nooptimization)調(diào)度器:只有一個子隊列,按照bio對象被接收時的順序處理請求。cfq(completefairqueuing)調(diào)度器:bio對象被接收后,獲取發(fā)送該bio對象的進(jìn)程ID,根據(jù)散列函數(shù),將進(jìn)程ID映射到6411個子隊列的某個隊列中,再處理各個子隊列中一定量的請求。這樣,每個進(jìn)程的I/O請求都會被公平執(zhí)行。deadline調(diào)度器:分別用不同的隊列來維護(hù)讀請求和寫請求。將接收的bio對象根據(jù)其對應(yīng)的扇區(qū)位置插入到請求隊列中最合適的位置(位置的排列以盡量減少磁盤頭的移動為原則)。但是,當(dāng)新的bio對象被不斷插入到請求隊列的前方時,隊列后面的請求恐怕就會長時間得不到處理,因此需要優(yōu)先處理一定時間內(nèi)(讀請求為0.5s,寫請求為5s)沒有得到處理的請求。anticipatory調(diào)度器:在deadline調(diào)度器的基礎(chǔ)上,追加了“預(yù)測”下一個bio對象的功能。例如,當(dāng)收到進(jìn)程A發(fā)出的讀請求后緊接著又收到了來自進(jìn)程B的請求時,就可以預(yù)測進(jìn)程A可能很快會發(fā)出另一個讀請求,這種情況下就要在調(diào)度進(jìn)程B的請求之前延遲一段時間(0.7秒左右),以等待來自進(jìn)程A的下一個讀請求。這些用來處理請求的不同I/O調(diào)度方法也被稱為“電梯算法”。因為要在最大限度減少磁盤頭移動的情況下,讀取和寫入盡可能多的數(shù)據(jù),這就好比大廈里的電梯,通過最少的運動承載盡可能多的人。最早在Linux中使用的電梯算法是由Linus先生設(shè)計的,因此過去也曾被稱為“Linus電梯”。RHEL6中默認(rèn)的I/O調(diào)度器是cfq。如果需要對單個硬盤所采用的I/O調(diào)度器進(jìn)行修改,可以通過echo命令在sys文件系統(tǒng)的特殊文件/sys/block/<磁盤名>/queue/scheduler中寫入I/O調(diào)度器的名稱(noop、anticipatory、deadline或cfq)。下面就是一個變更I/O調(diào)度器的例子,將/dev/sda當(dāng)前使用的cfq調(diào)度器更改為了deadline調(diào)度器。#cat/sys/block/sda/queue/scheduler
noopanticipatorydeadline[cfq]
#echo"deadline">/sys/block/sda/queue/scheduler
#cat/sys/block/sda/queue/scheduler
noopanticipatory[deadline]cfq
如果只是確認(rèn)當(dāng)前的I/O調(diào)度器,也可以使用lsblk命令。如下SCHED部分表示的就是當(dāng)前所采用的I/O調(diào)度器。#lsblk-t
NAMEALIGNMENTMIN-IOOPT-IOPHY-SECLOG-SECROTASCHEDRQ-SIZE
sda051205125121cfq128
├─sda1051205125121cfq128
├─sda2051205125121cfq128
├─sda3051205125121cfq128
└─sda4051205125121cfq128
如果需要修改系統(tǒng)默認(rèn)的I/O調(diào)度器,則在GRUB的配置文件/boot/grub/grub.conf的內(nèi)核啟動項中設(shè)置“elevator=deadline”。最后需要注意的一點是,對于被dev/sda等指定的設(shè)備,I/O調(diào)度器可以將其想象成圖1.1中扇區(qū)排列在物理磁盤的磁道上那樣的構(gòu)造,實現(xiàn)訪問的最優(yōu)化。但是在使用外部磁盤裝置的情況下,RAID陣列的邏輯驅(qū)動器(LUN)會被識別為/dev/sda等設(shè)備。這種時候,存儲裝置的控制器也能實現(xiàn)磁盤訪問的最優(yōu)化,就不需要Linux的I/O調(diào)度器去進(jìn)行過于復(fù)雜的優(yōu)化工作了。僅就一般而言,對于在數(shù)據(jù)庫服務(wù)器或服務(wù)器虛擬化環(huán)境這樣使用高性能外部存儲設(shè)備的復(fù)雜環(huán)境中的數(shù)據(jù)訪問,有時侯deadline調(diào)度器要比cfq調(diào)度器效率更高。順便說一下,雖然cfq調(diào)度器的解釋是“對每個進(jìn)程實行公平的I/O處理”,但是為了公平的處理,有時候也需要刻意營造一些不公平。大家或許并不熟悉,其實通過ionice命令可以對cfq調(diào)度器中的每一個進(jìn)程設(shè)置優(yōu)先級。優(yōu)先級有三類,分別是Realtime、Besteffort和Idle。和系統(tǒng)上的其他進(jìn)程相比較,Realtime級別的進(jìn)程的I/O是最為優(yōu)先被處理的。而Idle級別進(jìn)程的I/O正相反,只有在系統(tǒng)上所有進(jìn)程的I/O都處理完了的情況下才處理它。換句話說,除了這類進(jìn)程之外沒有別的進(jìn)程的I/O需要被處理,即系統(tǒng)處于空閑狀態(tài)時,才會對它進(jìn)行處理。Besteffort則是默認(rèn)的優(yōu)先級,基于cfq調(diào)度器的正常邏輯,公平地進(jìn)行I/O處理。對于優(yōu)先級為Realtime和Besteffort的進(jìn)程,還能在同一級別中依次指定數(shù)值為0~7的優(yōu)先級參數(shù),數(shù)值越小,優(yōu)先級越高。因此,對于那些由于特殊原因不允許延遲的進(jìn)程,就可以將其優(yōu)先級設(shè)置為Realtime級別。例如,RHEL6標(biāo)準(zhǔn)的HA集群系統(tǒng)(HighAvailabilityAdd-On)中,有一種被稱為“仲裁磁盤”(quorumdisk)的機制,它通過將數(shù)據(jù)定期寫入共享磁盤來確認(rèn)服務(wù)器是否運行正常。若寫入出現(xiàn)延遲,有時會誤報服務(wù)器發(fā)生故障,因此就可以考慮將該進(jìn)程(qdisk)的優(yōu)先級設(shè)置為Realtime級別。但是也要注意,如果某進(jìn)程有大量的I/O處理,若還將其優(yōu)先級設(shè)置為Realtime級別的話,其他進(jìn)程的處理就會完全停滯,從而引發(fā)其他問題。關(guān)于ionice命令的使用,可以參考手冊頁。要想確認(rèn)ionice的運行效果,則推薦試試下面這個命令。#ionice-c1ddif=/dev/zeroof=/tmp/tmp0bs=1Mcount=500oflag=direct&ionice-c3ddif=/dev/zeroof=/tmp/tmp1bs=1Mcount=500oflag=direct&wait
[1]18764
[2]18765
500+0recordsin
500+0recordsout
524288000bytes(524MB)copied,4.59358s,114MB/s
[1]-結(jié)束ionice-c1ddif=/dev/zeroof=/tmp/tmp0bs=1Mcount=500oflag=direct
500+0recordsin
500+0recordsout
524288000bytes(524MB)copied,9.3951s,55.8MB/s
[2]+結(jié)束ionice-c3ddif=/dev/zeroof=/tmp/tmp1bs=1Mcount=500oflag=direct
這個例子中有兩個同時執(zhí)行的dd命令,這里dd命令用于導(dǎo)出500M大小的文件,它們的優(yōu)先級分別被設(shè)置為Realtime和Idle。Idle優(yōu)先級的I/O處理完全被推遲,在Realtime優(yōu)先級的dd命令結(jié)束后,Idle優(yōu)先級的dd命令才開始執(zhí)行。這樣一來,Idle優(yōu)先級的執(zhí)行時間正好是Realtime優(yōu)先級的兩倍(圖1.11)。圖1.11Realtime級別和Idle級別dd命令中的指定選項oflag=direct,表示直接寫入物理磁盤而不使用磁盤高速緩存,常常被用來測量物理磁盤的性能。至于最后wait命令的含義,我們將在下一節(jié)中進(jìn)行說明。8此處為日文資料?!g者注9RHEL6的mke2fs命令,以及tune2fs命令對應(yīng)于ext4文件系統(tǒng)。mkfs.ext4命令,等同于“mke2fs-text4”。10Linux初始RAM磁盤initrd是系統(tǒng)引導(dǎo)過程中掛載的一個臨時根文件系統(tǒng),它與RAM磁盤空間是兩個概念?!g者注11默認(rèn)為26=64?!g者注1.3控制進(jìn)程就等于控制Linux眾所周知,Linux上的工作都是通過進(jìn)程來執(zhí)行的。若把系統(tǒng)的各種行為擬人化,進(jìn)程的一生便是時而穩(wěn)定,時而“死去”又“活來”,可謂十分曲折。有的進(jìn)程甚至每天都被嚴(yán)密地監(jiān)視著。在本節(jié),我們將再次探討進(jìn)程管理機制的基本知識,看看這種機制是如何支撐和左右這些進(jìn)程的命運的。尤其在理解了進(jìn)程的fork之后,腳本的創(chuàng)建技術(shù)將得到質(zhì)的提高。使用fork來編寫腳本的方法,在本書3.4.3節(jié)中亦有介紹。1.3.1fork和exec分別是進(jìn)程的分身和變身登錄系統(tǒng)控制臺時,需在“l(fā)ogin:”提示符處輸入用戶名進(jìn)行登錄。這里“l(fā)ogin:”提示符表示的是接收用戶名的輸入,執(zhí)行該步驟的是mingetty進(jìn)程。登錄成功后,命令提示符下顯示bash啟動。確切地說,是在bash進(jìn)程啟動時,即顯示相應(yīng)的命令提示符。然后,在命令提示符下運行l(wèi)s命令啟動ls進(jìn)程,可以顯示當(dāng)前目錄下的文件名。大家可能覺得這些都是小兒科,實際上,這一連串進(jìn)程動作的發(fā)生隱藏了一個至關(guān)重要的玄機。我們都知道,在Linux上創(chuàng)建進(jìn)程有fork和exec兩種方法,大家能準(zhǔn)確地說出這兩者的區(qū)別嗎?干脆來做一個小小的實驗吧。首先,在運行級別3下啟動一個Linux服務(wù)器,之后SSH遠(yuǎn)程登錄,查看mingetty進(jìn)程的執(zhí)行情況。#ps-ef|grep"mingett[y]"
root16921019:21tty100:00:00/sbin/mingetty/dev/tty1
root16941019:21tty200:00:00/sbin/mingetty/dev/tty2
root16961019:21tty300:00:00/sbin/mingetty/dev/tty3
root17001019:21tty400:00:00/sbin/mingetty/dev/tty4
root17021019:21tty500:00:00/sbin/mingetty/dev/tty5
root17041019:21tty600:00:00/sbin/mingetty/dev/tty6
grep命令的參數(shù)中,通過將它最后一個字母y寫成[y]的方法,可以確保grep進(jìn)程名的結(jié)果中不包含有與進(jìn)程名不符的信息12。這里找出了6個mingetty進(jìn)程。這六個虛擬控制臺,可以通過Ctrl+Alt+F1~F6分別切換到它們對應(yīng)的“l(fā)ogin:”提示符下。12思考一下,為什么grep命令中指定的檢索字符串就可以順利地使用正則表達(dá)式呢?在控制臺中按下Ctrl+Alt+F1,出現(xiàn)“l(fā)ogin:提示符”,輸入用戶名,然后輸入后回車,出現(xiàn)輸入密碼的提示。這里請先不要輸入密碼。這里再次在SSH遠(yuǎn)程登錄的終端,通過ps命令查看mingetty進(jìn)程。#ps-ef|grep"mingett[y]"
root16941019:21tty200:00:00/sbin/mingetty/dev/tty2
root16961019:21tty300:00:00/sbin/mingetty/dev/tty3
root17001019:21tty400:00:00/sbin/mingetty/dev/tty4
root17021019:21tty500:00:00/sbin/mingetty/dev/tty5
root17041019:21tty600:00:00/sbin/mingetty/dev/tty6
mingetty進(jìn)程的數(shù)量減少了一個,ID為1692的mingetty進(jìn)程似乎消失了。難道這個進(jìn)程接收一個用戶名就會消失嗎?并非如此。這一次,用ps命令檢索進(jìn)程ID。#ps-ef|grep"169[2]"
root16921019:21tty100:00:00/bin/login--
顯示的是login進(jìn)程。知道為什么會這樣嗎?事實上,mingetty進(jìn)程在exec()系統(tǒng)調(diào)用的作用下,已經(jīng)轉(zhuǎn)變?yōu)閘ogin進(jìn)程了(圖1.12左圖)。圖1.12exec和fork中進(jìn)程的變化Linux的進(jìn)程,除了進(jìn)程主程序代碼外還有其他各種各樣的信息,比如用于識別進(jìn)程的進(jìn)程ID就是其中之一。除此之外,還有用于和其他進(jìn)程或文件交換數(shù)據(jù)的管道、文件描述符等。exec的作用是舍棄進(jìn)程原本攜帶的信息,在進(jìn)程執(zhí)行時用新的程序代碼替代調(diào)用進(jìn)程的內(nèi)容。mingetty進(jìn)程的工作則是接收登錄用戶名,但之后對密碼的驗證處理工作則移交給login進(jìn)程繼續(xù)完成。圖1.13是mingetty進(jìn)程中運行exec的部分源代碼。每行開頭的編號表示源代碼中實際的行號。454行的函數(shù)execl,通過exec()系統(tǒng)調(diào)用切換到變量loginprog所指定的程序中去(這個例子中是/bin/login)13。這之后執(zhí)行的便是/bin/login進(jìn)程,因此通常455行之后的代碼便不會再運行了。只有在exec()系統(tǒng)調(diào)用出現(xiàn)失敗的情況下,才會運行455行之后的代碼。13調(diào)用exec()系統(tǒng)調(diào)用的C語言函數(shù)有execl、execlp、execle、execv、execvp等。execl和execv,由于命令的參數(shù)的傳遞方法的不同,即便最后都附加p,在PATH環(huán)境變量中進(jìn)行命令檢索時也仍有區(qū)別。mingetty.c454execl(loginprog,loginprog,autologin?"-f":"--",logname,NULL);
455error("%s:can'texec%s:%s",tty,loginprog,strerror(errno));
456sleep(5);
457exit(EXIT_FAILURE);
圖1.13mingetty中運行exec的部分源代碼之后,exec開始執(zhí)行l(wèi)ogin進(jìn)程,在接收密碼輸入完成用戶認(rèn)證后,便啟動用戶的bash進(jìn)程。之前出于實驗需要中斷了密碼的輸入,實際上,只有輸入密碼才算完成了登錄操作。在輸完密碼的情況下,我們再次檢索同一個進(jìn)程的ID。#ps-ef|grep"169[2]"
root16921019:21?00:00:00login--root
roo29tty100:00:00-bash
login進(jìn)程仍然保留了與之前相同的進(jìn)程ID(1692)。另外,此次檢索結(jié)果中還包含了bash進(jìn)程。bash進(jìn)程本身的進(jìn)程ID(1818)與檢索的進(jìn)程ID并不匹配,但是它的父進(jìn)程的進(jìn)程ID(1692)與grep檢索中的進(jìn)程ID互相匹配了(ps–ef命令的輸出中依次包含用戶ID、進(jìn)程ID以及父進(jìn)程的進(jìn)程ID)。這說明bash進(jìn)程是作為login進(jìn)程的子進(jìn)程開始啟動的。通常我們說“fork一個進(jìn)程”,指的是通過父進(jìn)程創(chuàng)建一個子進(jìn)程。但現(xiàn)在的情況是,bash進(jìn)程并不是從login進(jìn)程中直接fork出來的。從圖1.12的右圖可以看出,fork生成的子進(jìn)程是一個與正在運行的進(jìn)程完全相同的副本。login進(jìn)程通過fork生成一個自身的副本后,又在子進(jìn)程中通過exec啟動bash,這一技術(shù)簡稱為“fork-exec”。圖1.14描述了它的整個流程。圖1.14從虛擬控制臺登錄時伴隨的進(jìn)程的變化如果諸位仍覺得對fork-exec一頭霧水,那么就從login的源代碼中看看fork-exec實際的執(zhí)行過程吧。Linux和開源最偉大的地方就是無論什么都能親自探尋。關(guān)于如何學(xué)習(xí)源代碼,在本書的第4章中也有所介紹,這里只是暫時先在圖1.15中給出答案。以//標(biāo)記的注釋,是筆者自己補充的。login.c1183child_pid=fork();
//子進(jìn)程的進(jìn)程ID賦值給父進(jìn)程的child_pid
//子進(jìn)程的child_pid中代入0
1184if(child_pid<0){
//fork失敗時的錯誤處理
//(部分源代碼省略)
1189exit(0);
1190}
1191
1192if(child_pid){
//父進(jìn)程從這里開始執(zhí)行
//這個例子中,等子進(jìn)程結(jié)束后,自己也就結(jié)束了
//(部分源代碼省略)
1201/*waitaslongasanychildisthere*/
1202while(wait(NULL)==-1&&errno==EINTR)
1203;
//(部分源代碼省略)
1206exit(0);
1207}
1208
//子進(jìn)程從這里開始執(zhí)行
1209/*child*/
1210
//(部分源代碼省略)
//子進(jìn)程通過exec變換為bash
1280execvp(childArgv[0],childArgv+1);
圖1.15login中進(jìn)行fork-exec的源代碼首先,在1183行代碼中直接執(zhí)行了fork。這里的進(jìn)程一分為二,且都是從1184行開始繼續(xù)執(zhí)行的。當(dāng)然這樣并沒有意義,因為這兩個進(jìn)程是完全相同的,所以之后子進(jìn)程需要通過exec變換為bash進(jìn)程。這里用到一個小技巧,即把fork的返回值賦給變量child_pid。fork執(zhí)行失敗時,父進(jìn)程返回負(fù)值。fork執(zhí)行成功時,父進(jìn)程以及通過fork創(chuàng)建的子進(jìn)程返回的值卻不相同。父進(jìn)程的child_pid值為子進(jìn)程的進(jìn)程ID,而子進(jìn)程的child_pid值為0。因此,父進(jìn)程在1192行的if語句上條件成立,并執(zhí)行if語句中的代碼。這個例子中,父進(jìn)程會一直等待子進(jìn)程結(jié)束,直到子進(jìn)程退出時,父進(jìn)程才結(jié)束。子進(jìn)程跳過1192行的if語句,從1209行處開始執(zhí)行。這個例子中顯示的是在1280行調(diào)用exec,進(jìn)程變換為bash繼續(xù)執(zhí)行。fork也可以采用Perl等腳本語言來實現(xiàn)。如果你不擅長C語言編程,那就請務(wù)必牢記這里所介紹的fork的處理技術(shù)。最后來看看進(jìn)程結(jié)束的過程吧。首先,父進(jìn)程login通過執(zhí)行圖1.15中1202行的wait函數(shù),一直休眠直到子進(jìn)程結(jié)束。如下例所示,通過ps命令確認(rèn)進(jìn)程的狀態(tài),可看到附加的表示休眠狀態(tài)的S符號。#psaux|grep"logi[n]"
root16920.00.2770042532?Ss19:210:00login--root
這時在已登錄的虛擬控制臺上顯示的bash命令提示符處,輸入exit進(jìn)行用戶注銷。此時,通過exit()系統(tǒng)調(diào)用,bash進(jìn)程被終止,同時發(fā)送CHLD信號給父進(jìn)程login。接收到CHLD信號的父進(jìn)程login會退出wait函數(shù),同時結(jié)束進(jìn)程。wait是一個函數(shù),它讓父進(jìn)程在接收到子進(jìn)程CHLD信號之前一直保持休眠狀態(tài)。而另一方面,子進(jìn)程向父進(jìn)程發(fā)送CHLD信號,直到父進(jìn)程接收為止,子進(jìn)程都處于“僵尸進(jìn)程”的狀態(tài)。如果父進(jìn)程設(shè)置為忽略CHLD信號,子進(jìn)程就會一直保持僵尸狀態(tài)。在通過psaux來查看進(jìn)程狀態(tài)時,僵尸狀態(tài)會被標(biāo)記為Z,信息末尾會顯示<defunct>。關(guān)于CHLD信號等這一類的進(jìn)程信號,請參見相關(guān)書籍。圖1.16表示的是bash進(jìn)程在被exit終止后的一系列流程。從圖中可以看到,login進(jìn)程在結(jié)束之際向某處發(fā)送了CHLD信號,那么誰會接收到這個信號呢?圖1.16從虛擬控制臺退出時伴隨的進(jìn)程的變化從之前ps命令的輸出中可以看到,login進(jìn)程的父進(jìn)程是進(jìn)程ID為1的init進(jìn)程。因此,init進(jìn)程將會接收CHLD信號,這時login進(jìn)程就可以從僵尸狀態(tài)中解放出來。另一方面,接收到CHLD信號后,init進(jìn)程會檢測到login進(jìn)程(或是原始的mingetty進(jìn)程)已經(jīng)終止了,于是會再度啟動新的mingetty進(jìn)程,這樣便可以在虛擬控制臺上再次登錄了。啟動mingetty進(jìn)程需要用到之前介紹的fork-exec,因此mingetty進(jìn)程相當(dāng)于init進(jìn)程的子進(jìn)程。此外,一直到RHEL5,init進(jìn)程都是根據(jù)配置文件/etc/inittab來重新啟動mingetty進(jìn)程的。但如今發(fā)展到RHEL6,init進(jìn)程的啟動機制已替換為被稱作“Upstart”的新機制,啟動時采用的是/etc/init下的配置文件。關(guān)于Upstart,5.2節(jié)會有詳細(xì)的介紹。最后介紹一下與fork-exec機制相關(guān)的進(jìn)程監(jiān)控的問題。用fork-exec創(chuàng)建新的進(jìn)程時,最初fork的瞬間,子進(jìn)程的進(jìn)程名和父進(jìn)程的進(jìn)程名是相同的。之后才通過exec變更為新的過程名。因此,在進(jìn)行進(jìn)程監(jiān)視,對特定進(jìn)程名的進(jìn)程數(shù)量進(jìn)行檢查的時候,在fork-exec執(zhí)行的那一瞬間,需注意進(jìn)程數(shù)量可能大量增加。如果設(shè)定為“不允許存在同樣命名的進(jìn)程”的話,fork-exe和監(jiān)視間隔的時間會出現(xiàn)微妙的一致,從而誤檢測到異常的進(jìn)程數(shù)。這種現(xiàn)象并不少見,因此為了避免判斷時帶來麻煩,請務(wù)必注意到fork-exec的存在。1.3.2作業(yè)控制中的各項任務(wù)處理前文介紹了進(jìn)程啟動的基本原理。下面再來介紹一些實用的技術(shù)吧。首先,在shell命令提示符下運行命令,通常在命令執(zhí)行完畢后,命令提示符會再度出現(xiàn),這與login進(jìn)程啟動bash進(jìn)程的流程(圖1.14)是一樣的。bash進(jìn)程首先響應(yīng)命令,通過fork-exec創(chuàng)建了一個新的進(jìn)程,之后便會一直處于休眠狀態(tài)直到子進(jìn)程結(jié)束。接著bash進(jìn)程接收到CHLD信號,確認(rèn)子進(jìn)程已終止,再次顯示命令提示符,提示接收下一個命令。在命令的末尾加上“&”符號,可以讓命令在后臺運行。這種情況和上文一樣,bash進(jìn)程會通過fork-exec創(chuàng)建新的進(jìn)程,不同的是,此時bash進(jìn)程不再需要等待子進(jìn)程結(jié)束,便可以直接顯示命令提示符,提示接收下一條命令。在執(zhí)行比較花時間的命令時,讓多條命令并行執(zhí)行不失為一種便利的方法。但這里存在一個應(yīng)用的問題。怎樣才能讓多條命令并行執(zhí)行,并且等待所有命令都執(zhí)行結(jié)束呢?舉個例子,可以考慮通過shell腳本實現(xiàn)SSH在10臺服務(wù)器上執(zhí)行遠(yuǎn)程命令,并等待所有服務(wù)器上的命令執(zhí)行完畢。圖1.17是筆者實際使用過的shell腳本的例子,其目的是在三臺服務(wù)器(node01~node03)上啟動群集服務(wù)(clstart)[5]。為方便起見,將該腳本命名為clstart_all.sh。TechnicalNotes[5]HighAvailabilityAdd-On設(shè)計和運用入門“集群的啟動順序”\h/enakai/rhel6-rhcs-guidepreview-87581121414此處為日文資料。——譯者注例1在每一臺服務(wù)器上執(zhí)行#!/bin/sh
sshnode01/usr/local/bin/clstart
sshnode02/usr/local/bin/clstart
sshnode03/usr/local/bin/clstart
例2命令執(zhí)行完之前結(jié)束#!/bin/sh
sshnode01/usr/local/bin/clstart&
sshnode02/usr/local/bin/clstart&
sshnode03/usr/local/bin/clstart&
例3命令執(zhí)行完之后退出#!/bin/sh
sshnode01/usr/local/bin/clstart&
sshnode02/usr/local/bin/clstart&
sshnode03/usr/local/bin/clstart&
wait
圖1.17在多個服務(wù)器上并行執(zhí)行命令的Shell腳本(clstart_all.sh)如例1中所示,node01運行clstart結(jié)束后,node02接著執(zhí)行,即每一臺服務(wù)器按順序依次執(zhí)行。這顯然是很浪費時間的。因此,在例2中,筆者嘗試在后臺執(zhí)行每個命令。這種情況下,三臺服務(wù)器能同時正確執(zhí)行clstart命令。但是,在每一臺服務(wù)器上的clstart命令運行結(jié)束前,腳本的運行就已經(jīng)結(jié)束了。這里就出現(xiàn)了一個問題,即沒法在所有服務(wù)器的群集服務(wù)啟動完成后,再接收下一條輸
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年農(nóng)業(yè)信息化軟件采購及推廣應(yīng)用合同3篇
- 2024年度商業(yè)地產(chǎn)買賣合同(含物業(yè)管理協(xié)議)3篇
- 2024版人工智能語音識別技術(shù)知識產(chǎn)權(quán)許可合同2篇
- 2024墻體圖文廣告制作與城市形象宣傳合同3篇
- 2024商鋪房租合同附帶線上線下營銷支持3篇
- 2024年商鋪租賃合同范本:簡易操作商鋪租賃協(xié)議14篇
- 2024年健身教練中介合同3篇
- 2024年度商品混凝土運輸與交付責(zé)任合同3篇
- 2024年度云計算服務(wù)與大數(shù)據(jù)分析承包合同2篇
- 2024版二房東租賃合同模板:商業(yè)空間租賃服務(wù)
- 代碼走查檢查單
- 應(yīng)急醫(yī)療救援無人機系統(tǒng)
- 智能光伏清潔機器人控制系統(tǒng)設(shè)計概述
- 業(yè)主授權(quán)租戶安裝充電樁委托書
- 橋式起重機定期檢查記錄表
- 微觀經(jīng)濟學(xué)(山東聯(lián)盟-山東財經(jīng)大學(xué))智慧樹知到期末考試答案2024年
- 數(shù)據(jù)可視化技術(shù)智慧樹知到期末考試答案2024年
- MOOC 警察禮儀-江蘇警官學(xué)院 中國大學(xué)慕課答案
- 三基考試題庫與答案
- 2024年廣東省2024屆高三二模英語試卷(含標(biāo)準(zhǔn)答案)
- 全飛秒激光近視手術(shù)
評論
0/150
提交評論