【梳理】簡明操作系統原理 第十二章 機械硬盤 RAID(內附文檔高清截圖)

參考教材:
Operating Systems: Three Easy Pieces
Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau
在線閱讀:
http://pages.cs.wisc.edu/~remzi/OSTEP/
University of Wisconsin Madison 教授 Remzi Arpaci-Dusseau 認爲課本應該是免費的
————————————————————————————————————————
這是專業必修課《操作系統原理》的複習指引。
在本文的最後附有複習指導的高清截圖。需要掌握的概念在文檔截圖中以藍色標識,並用可讀性更好的字體顯示 Linux 命令和代碼。代碼部分語法高亮。
操作系統原理不是語言課,本複習指導對用到的編程語言的語法的講解也不會很細緻。如果不知道代碼中的一些關鍵字或函數的具體用法,你應該自行查找相關資料。

十二 機械硬盤 RAID

1、機械硬盤(Hard disk drive,HDD)本身是按照扇區(sector)爲最小單位進行存儲的。以前,硬盤的扇區大小一般爲512 Bytes;較新的硬盤則採用4 KB作爲單個扇區的大小。但是4 KB扇區需要操作系統的支持,所以爲了使硬盤在較老的OS上能夠被識別,硬盤廠商通過固件(firmware)將4 KB大小的物理扇區模擬成512字節的邏輯扇區。

固件是安裝在設備的硬件中的軟件,和驅動(需要安裝在操作系統內)沒有明顯的界限,但一般而言固件要更加接近於硬件底層。通常情況下,固件不允許被修改。
硬盤對扇區的讀寫是原子性的。如果讀寫過程中突然斷電,未寫入的數據就會丟失。

2、機械硬盤內部有若干個盤片(platter),它們是圓形的,一般由鋁製成,表面極其光滑(你可以把報廢的盤片拆下來當鏡子用),雙面都附有磁性材料來存儲數據。盤片都被固定在主軸(spindle)上,隨主軸一起轉動。硬盤啓動後,盤片的轉速一般爲5400 RPM(轉 / 分)或7200 RPM。少數服務器硬盤轉速達到10000 RPM甚至15000 RPM。當然,現在也比較少見了。因爲高轉速對加工的要求很高,而且轉速過高可能導致盤片因爲原子間提供的向心力不足而直接破碎。另外,高轉速帶來的發熱量也是非常大的。盤片的直徑多爲2.5英寸或3.5英寸。以前有5.25英寸的硬盤,但是轉速也不能做得過快。
其它規格都相同的情況下,轉速越高,讀寫速率越快。7200 RPM的硬盤的讀寫速率一般高於5400 RPM的硬盤。
盤片被劃分爲大量的同心圓,每個同心圓稱爲一個磁道(track,有的軟件也寫作磁頭,但不要將其把用於讀取數據的磁頭搞混)。單個盤片的磁道數量非常大,目前每張盤片的容量可以做到2 TB。
每張盤片的每一面各有一個磁頭(disk head),與機械臂連接,被驅動電路控制,用於在不同的磁道、扇區進行讀寫。

如圖。磁盤啓動後,磁頭會迅速移到盤片上方。在磁道間讀寫時,磁頭的移動速度是非常快的。磁頭通過空氣動力學設計浮在盤片上方,距離盤片非常近。空氣過濾片過濾空氣中的灰塵。盤片對無塵的要求非常嚴格,所以不要自行拆開硬盤,否則這個硬盤很快就會報廢。硬盤中的永磁鐵的磁性非常大,如果你拆開了一個報廢的硬盤,玩永磁鐵的時候千萬要小心,否則在磁鐵與其它物體吸住的時候,你的手指很可能會馬上變成肉泥。

3、收到讀寫扇區的命令後,磁盤會找到扇區所在的磁道,磁頭會先從當前所在的位置移過去。這個過程需要的時間稱爲尋道時間(seek time)。具體來說,磁頭從當前位置開始加速,然後保持一定的速度滑行,再減速,最後靠在正確的磁道上。爲了使磁頭能正確定位磁道,最後一步耗費的時間也是最多的。
然後,磁盤等待扇區轉到磁頭可以達到的位置。差不多到達這個位置以後,磁頭就進行讀寫。這個等待的過程稱爲旋轉延遲(rotational delay)。
這時候,傳輸數據的過程才正式開始。讀一個扇區的速率自然是非常快的,因爲要在扇區因爲盤片的轉動而離開磁頭之前就將其讀取完畢。
讀寫完畢後,磁頭留在原位。因爲過度頻繁地移動磁頭會耗損其壽命。
由此我們得出:磁盤IO的總時間 = 尋道時間 + 旋轉延遲 + 傳輸時間。即
T_IO=T_S+T_R+T_t

4、現在的硬盤採用了磁道偏移(track skew)方式來劃分磁道和扇區。下面的圖中,右側是採用了該技術的硬盤:

注意對比兩張圖的扇區11和12、23和24的相對位置有什麼不同。這種方式能使順序讀取的過程中,磁頭切換下一條磁道讀取時,能夠直接從下一個扇區開始讀。如果不使用該方式劃分磁道和扇區,磁頭在切換下一個磁道時,下一個編號的扇區已經在切換磁道的過程中隨着盤片的旋轉而離開了磁頭的位置。若要繼續讀取此扇區,只能再等盤片轉一圈。
這兩張圖只是爲了便於理解而繪製的。事實上,在較新的硬盤中,外側的磁道擁有的扇區數要更多。現在說的“每磁道扇區數”是一個換算出來的平均值。
機械硬盤都會具有緩存(以前叫做磁道緩衝區(track buffer))。讀取數據時,被讀取的數據連同附近的數據一起被讀入緩存中,以此加快訪問速率。在寫入數據時,數據也會先寫入到緩存,之後再由硬盤正式寫入到盤片上。
磁盤在寫入時,有兩種方式,分別是write back和write through。使用前者時,只要寫入的數據全部交給了磁盤(即使有數據還在緩存內),就報告寫入已經完畢;使用後者時,只有數據真正寫入到盤片上,才報告寫入完畢。Write back方式看上去寫入速率更高,但如果在磁盤將緩存中的數據寫入的過程中斷電,未寫入盤片的數據將丟失。緩存加快讀寫速率的原理在第6章第10點已經講過了。

5、簡單學習了磁盤讀寫的基本步驟之後,很容易想到:順序讀取的速率一定遠遠高於隨機讀取,因爲隨機讀取意味着要耗費大量時間在尋道和旋轉延遲上。如果頻繁請求小文件的隨機讀寫,性能會降低得非常難看。在編寫代碼的時候也要注意,如果可能,儘量將小的IO湊在一起一次性進行。
由下面的幾張圖片可以看出順序讀寫和小文件讀寫的性能差距。如果是小文件隨機讀寫,性能就更低了(Pic via Anandtech)。並且,小文件大概率是在硬盤上隨機分佈的。

6、理論上,平均尋道時間是最大尋道時間的約1 / 3。下面我們來證明這個結論。
設磁道從0編號到N,N→+∞(一個磁盤具有非常多的磁道數量)。從任意一個磁道x尋道至y需要走過的路程近似用
|x – y| 個長度單位表示。於是所有的尋道軌跡的路程之和就是

由乘法原理,共有N2種不同的尋道請求。因此上式除以N2就得到平均的尋道路程。設尋道的平均速率是不變的,那麼平均尋道時間與最大尋道時間的比值就由兩種情況下磁頭走過的路程決定了。
因爲N很大,所以上面的式子可以近似爲積分式

我們先算內層積分。去掉絕對值,得:

上式已經可以直接解出,結果爲:

化簡併代入原積分式,得:

這個積分式也可以直接解出,結果爲:

如果訪問是完全隨機的,那麼N越大,N2次尋道中磁頭走過的總路程就越接近該值。將其除以N2,就得到平均尋道路程爲1 / 3倍的N。最大尋道路程自然就是從盤片的最外沿到最內沿,路程爲N。結論得證。

7、一系列IO請求產生(或累積)後,磁盤調度器(disk scheduler)負責調度這些磁盤IO請求。與進程 / 線程調度不同,我們一般無法得知進程 / 線程何時結束,但可以根據需要訪問的位置和磁頭的當前位置算出磁盤的尋道時間和延遲。因此磁盤調度器傾向於選擇最短作業優先(SJF)調度算法。
最短尋道時間優先(shortest seek time first,SSTF),或最短尋道優先(shortest seek first,SSF),是很早就產生的磁盤IO調度方法。目標磁道離磁頭的當前位置最近的IO請求會被最先處理。
但SSTF並不是萬能的,因爲磁盤的幾何結構並不爲操作系統所知,操作系統只把磁盤當成一個由塊組成的一維連續結構。不過這個問題非常容易解決,OS容易實現最近塊優先(nearest block first,NBF)算法,讓離訪問過的塊最近的IO請求最先被處理。
而且,SSTF容易讓部分請求長期飢餓,因爲硬盤總是最先響應離當前磁頭位置更近的尋道請求。

8、電梯調度,也稱SCAN,它的基本思想很簡單:不斷地由盤片外圈移至內圈,再由內圈移至外圈,如此往復,很像建築物裏的電梯那樣反覆升降。磁頭完整地從外圈移至內圈或從內圈移至外圈一次,稱爲一次掃描。這個算法總是從磁臂當前位置開始,沿磁臂的移動方向去選擇離當前磁臂最近的那個柱面的訪問者。如果沿磁臂的方向無請求訪問時,就改變磁臂的移動方向。如果某個請求在最近一次的掃描中已經處理過,它將不被立即處理。
SCAN算法有很多變體。F-SCAN在掃描進行的過程中凍結請求隊列,在掃描期間到來的請求全部被延後至下一輪掃描再處理。這確保了每個IO請求的飢餓時間都不長。
C-SCAN的C代表Circular(循環)。這種算法只從外圈向內圈掃描。一輪掃描完畢後,磁頭重新回到最外圈。這種算法對靠近內圈和外圈的IO請求更公平一點。雙向的往復掃描可能讓部分外圈和內圈的IO請求飢餓時間較長。
舉個生活中的簡單例子,你就能更好地體會電梯算法的優勢了:假如電梯裏只有你一人,你從30樓下到1樓,有個人從10樓進來了,按了15樓。如果電梯總是去往最近的樓層,那麼它就會先到15樓。如果15樓又有個人上來了,他按了13樓,電梯就到13樓;13樓又有個人上來了,他按了18樓,電梯就又上升到18樓……當輪到你到達1樓的時候,時間已經不知道過去多久了。

9、不過,SCAN和SSTF並沒有考慮盤片的旋轉造成的影響。在介紹最短定位時間優先(shortest positioning time first,SPTF,或最短訪問時間優先,shortest access time first,SATF)之前,先舉一個例子:

現在在扇區30。一堆磁盤IO請求過來了,一個是16,一個是8。先處理哪個呢?我們進行分類討論。
如果尋道時間比旋轉延遲長得多,使用SSTF及其變種更佳,先訪問扇區16;但如果旋轉延遲比尋道時間長,訪問8則更優。因爲如果訪問16則意味着要等盤片轉上差不多一圈才能訪問到它。
但在較新的機械硬盤中,尋道和旋轉時間一般差不多(當然在有些情況下有區別),於是SPTF算法就能更好發揮性能了。但這個方法更難被操作系統實現,因爲操作系統並不能知道磁道邊界在哪裏,也不知道此時磁頭在哪個位置,所以這個算法通常由磁盤自行實現。

10、以往,操作系統負責全部的磁盤調度。而現代系統中,磁盤負責大部分的調度。操作系統通常只簡單告訴磁盤它認爲的一些最優位置,磁盤便接手剩餘的調度決策。
OS也負責將鄰近位置的磁盤IO合併。這可以減少IO請求的數量,減輕硬盤控制芯片的壓力,並且還能提升讀寫速率。
此外,OS如何知道當IO數量非常少的時候要等待多久?有的OS選擇令磁盤連續工作(work-conserving),於是一有磁盤IO到來就立刻讓磁盤進行讀寫;而相對的是預期磁盤調度(anticipatory disk scheduling),當IO請求非常少時,先等待一定時間,以便在收集到更多的IO請求後做出一個更優的調度方案,也可以將鄰近區域的磁盤IO請求合併,提升性能。能力足夠的同學可以查閱相關的論文或Linux內核代碼。

11、我們總是希望硬盤能夠更大、更快。一張4K的BD最大容量至少爲66 GB,有的盤還更大,把這些電影抓到硬盤裏,只需要幾十部,一塊5 TB的移動硬盤就差不多要滿了;也許你還下載了很多數字音樂,它們甚至是Hi-Res或DSD規格的;你還在B站或者YouTube下載了很多很有趣的視頻;你還會拿相機或攝像機拍攝很多高質量的照片和錄像;你寫了很多小說和歌曲,畫了很多漫畫……這些無不對存儲容量、速率和可靠性上提出了更高的要求。
廉價磁盤冗餘陣列(Redundant Array of Inexpensive Disks,RAID)一詞在1980年代末由UC Berkeley的一組研究人員引入。這個時間前後,許多研究者也不約而同地產生了相似的思想。
從外部看,RAID是一塊磁盤,可以作爲整體進行讀寫。但RAID實際上具有多個磁盤,還可以有內存,以及專門管理這些磁盤的處理器。硬RAID已經很接近一個計算機系統,只不過其主要任務是管理磁盤。

12、爲計算機添加新的功能時,應該儘量做到透明,也就是說OS基本不用作多少改動就可以讓新功能正常運行。RAID是一個非常好的例子。因爲你基本上完全可以把RAID當作一塊磁盤來用,在OS層面上幾乎不需要進行什麼更改。把一塊磁盤換成一個RAID,不用改動一行代碼;在RAID安裝完畢後,原有的OS和應用程序可以直接繼續運行。透明增強了硬件的可部署性(deployability),用戶無需擔心軟件不與新硬件兼容。

13、當文件系統向RAID發起一個(邏輯)IO請求時,RAID本身要確定需要訪問的內容位於哪些磁盤,然後向相應的磁盤發起(物理)IO。RAID的實現是很複雜的:微控制器需要對磁盤正確操作,DRAM負責暫存常用的數據塊,有時還要對數據進行校驗。

14、評價一個RAID的常見指標有:
(1)容量。同樣容量的磁盤,實現不同的RAID後,剩餘的可用容量是不同的。
(2)可靠性。這個RAID系統最多能容忍多少磁盤同時損壞?
(3)性能。性能的重要性就不用多說了。

15、RAID 0將數據分散存儲在各個磁盤上。假設將一個文件分成很多份(前16份編號0到15),由4塊硬盤組件RAID 0,那麼它的分佈是這樣的:

可以看出,數據按照RR(round-robin)的方式分配到各個磁盤。在上表中橫跨一整行的每部分數據都稱爲一個條帶(stripe)。RAID將數據按照塊(chunk)劃分,同一塊被寫入一個磁盤。如果將塊大小(chunk size)擴大兩倍,數據的分佈就變成這樣:

塊大小爲2的整數次方倍,一般爲32 KB或64 KB,其它值亦可。
塊大小是影響RAID性能的重要因素。塊大小較小時,文件被打散成更多份,於是在訪問單個文件的時候,需要訪問的部分具有更大的機率位於不同磁盤,使得併發度更高;但是如果要在文件中定位,也需要更多的時間。塊大小較大時,情況相反:訪問單個文件的時候,需要訪問的部分具有更大的機率位於更少的磁盤甚至都位於同一個磁盤,使得併發度更低乃至和單個磁盤的讀寫性能沒有區別;但如果要在文件中定位,則需要更少的時間。塊大小需要根據應用場景和硬盤本身的特點來決定,不存在一個普遍適用的值。
下面我們從第14點說的三個指標入手,來評估RAID 0。
在容量上,RAID 0做得很完美:RAID 0的總容量是各個硬盤的容量之和。但是要注意:如果使用不同容量的磁盤來組成 RAID-0時,由於數據是一直等量依序放置到不同磁盤中,當小容量的磁盤用完後,所有的數據都將被寫入到剩餘的磁盤去。此時的性能就變差了。在性能上,RAID 0也很優秀:有幾塊磁盤組成RAID 0,讀寫性能最高就能達到單塊磁盤的幾倍。當然,數據不大於塊大小的時候,它就只能落在一個磁盤上,讀寫性能就沒有提升了。但是,RAID 0不具備任何冗餘。如果組成RAID 0中的任何一塊磁盤損壞,基本就意味着存儲在這個陣列上的全部數據都丟失了,因爲所有文件都是被儘可能高度分散並存儲的,只有在非損壞磁盤上的那些不大於塊大小的小文件能夠逃過一劫。
在讀寫的時候,各塊硬盤的工作狀態不一定相同,有的盤可能恰好在這時具有更大的尋道時間和旋轉延遲。這部分延遲會導致RAID的實際讀寫速率要比理論上慢一點。

16、RAID 1將數據鏡像(mirror)存儲,每個磁盤都是另一塊磁盤的鏡像:

當然,這只是其中一種數據組織方式。你還可以在RAID 1的基礎上將數據條帶化存儲。RAID-10(RAID 1+0)先將數據複製爲鏡像,再進行條帶存儲;而RAID-01(RAID 0+1)先條帶化,再鏡像化。
讀取數據時,RAID 1可以從多個磁盤鏡像中讀取;而寫入的時候,必須向每個鏡像盤統一寫入相同內容,以確保冗餘性。
由於RAID 1是完全的鏡像,因此可用容量爲總容量除以副本數量。一般同一個數據只存儲2份,只有十分關鍵的數據纔會啓用多個鏡像存儲。以兩份副本爲例,RAID 1最多可以容忍一半的盤損壞,當然前提是沒有任何兩塊互爲鏡像的盤同時損壞;點背的時候,雖然只壞了兩塊盤,但壞的正好是互爲鏡像的盤,那這部分數據就確確實實丟失了。

17、RAID 4則帶有奇偶校驗(parity check)。相比完全鏡像的RAID 1,RAID 4存儲同樣內容需要花費的磁盤數量少得多,但冗餘度就沒有那麼高。

數據依然是條帶分佈的,每個條帶都配有專門的一塊磁盤作爲校驗盤。
校驗位的數據是通過奇偶校驗得出的。如果有n個二進制位參與奇偶校驗,則從左往右共做(n – 1)次異或運算。由異或的性質得:參與運算的位中,若1的個數是奇數,則校驗位爲1;若1的個數是偶數,則校驗位爲0。校驗時,每塊磁盤對應塊中的對應位一同進行異或,結果寫在校驗盤中對應的位。
下圖以4塊盤各自的位於磁盤最前面的一個數據塊的前4位爲例。在4磁盤1校驗盤的結構下,可以看出數據塊是在各個非校驗磁盤中交錯分佈的;圖中展示的四個數據塊的第0、1、2、3位分別有3、1、1、2個1,校驗位爲1、1、1、0。

在非校驗磁盤中,數據的組織方式與RAID 0一樣。而校驗盤不負責數據的存儲,因此RAID 4的可用容量是非校驗磁盤的總容量之和。RAID 4最多允許非校驗盤中損壞1塊,這1塊的數據可以由其它非校驗盤和校驗盤中的信息重構出來:校驗位描述了參與異或運算的1是奇數個還是偶數個。而參與運算的位數又是已知的,所以可以直接推斷出缺失的數據。但如果非校驗盤損壞了超過1塊,就無法重構數據了。
下面分析RAID 4的性能。對順序讀取,其情況與RAID 0類似,最高性能爲單盤順序讀取性能×非校驗磁盤個數。但是如果要讀取的內容正好都落在同一塊磁盤,性能就沒有提升。在順序寫入的時候,寫入的同時需要修改相應的校驗位,但位運算比磁盤的機械動作快得多,而且對校驗盤的讀寫與對非校驗盤的讀寫相對獨立,不會拖慢數據讀寫,所以最高速率也能達到單盤順序寫入性能×非校驗磁盤個數。
在隨機讀取時,其性能也與RAID 0類似:有幾塊非校驗磁盤組成RAID 4,讀寫性能最高就能達到單塊磁盤的幾倍。當然,數據不大於塊大小的時候,它就只能落在一個磁盤上,讀寫性能就沒有提升了。但在隨機寫入時,情況就比較棘手了:由於寫入數據較小,因此有很多或者全部需要進行寫入的條帶中,不是所有的位置都會被寫入。但寫入新數據可能會導致校驗位改變,因此在寫入某一條帶上的塊時,需要一併讀取同一條帶上其它數據塊的未修改數據,並重新計算新的校驗碼。當非校驗盤的塊數很多時,造成的性能影響也非常大。
有一種方式可以減小這種性能影響。在寫入數據塊之前,把這一塊的舊數據讀出來,然後比對各個位要寫入的數據是否與這一位的原數據不同。如果是,就意味着校驗位要改變。如果不是,這一位校驗位保持不變。於是,寫入一個塊的數據在非校驗盤上實際需要的操作就是一次讀一次寫。更坑爹的是,由於在非校驗盤每寫入一個塊,都要把校驗盤對應的位修改一次,因此校驗盤會卡住整個寫入進程,導致對非校驗盤的寫入必須等一個塊寫完並修改相應的校驗位後再寫入下一個塊而不能併發。因此,隨機寫入的性能等於:單盤隨機寫入性能÷2。
(這裏我覺得有點不對勁。因爲這種寫入策略非常蠢,實際上應該可以把一個條帶上多個塊的隨機寫入操作合併,併發地寫入,一次性修改校驗位。這裏我再去求證一下。RAID 2 / 3 / 4沒有RAID 0 / 1 / 5 / 10常用,這裏大家先不管它。)

18、爲了(至少部分)解決校驗式RAID的小數據讀寫性能大打折扣的問題,RAID 5應運而生。RAID 5的校驗數據的分佈是這樣的:

RAID 5的很多地方和RAID 4很像。RAID 5同樣只允許1塊盤失效,順序讀寫性能和RAID 4是一樣的。RAID 5的隨機讀取性能要好一點,因爲在校驗數據佔有的比例相同的情況下,可以多用一塊盤進行讀寫(校驗數據不再由專門的一塊不參與讀寫的磁盤進行存儲)。相比RAID 4,RAID 5的隨機寫入性能的增長令人印象深刻。RAID 5的隨機寫操作可以併發。其隨機寫入的速率是:單盤隨機寫入性能×磁盤塊數÷4,除以一個因子4是因爲採用奇偶校驗的RAID的每個寫操作實際上都要進行4個操作:一次是寫入數據本身,一次是讀寫入位置的舊數據,一次是讀所屬的校驗塊,一次是寫入新的校驗塊。
(RAID 5的隨機寫入性能這裏也存疑。)

19、還有其它級別的RAID,比如RAID 2、RAID 3和RAID 6等。RAID 6最多允許2塊盤損壞。在RAID中的磁盤發生故障時,RAID控制器必須立刻探測到併發出告警。用戶接到警報後,需要及時進行重建。有時候,RAID系統會有一個熱備盤(hot spare disk)。如果RAID裏其中一個盤壞了,這個熱備盤就會頂替RAID裏的那個壞盤,同時把壞盤上面的數據原樣做出來並存儲在熱備盤中。於是RAID系統允許同時損壞的盤數就多了1塊。

20、RAID通過如下的公式來定位數據塊所在的磁盤和盤內位置(設數據塊的邏輯塊號爲A):
Disk = A % number_of_disks
Offset = A / number_of_disks

21、設想在多個磁盤寫入數據的過程中突然斷電、系統出現致命故障的情況,這會導致數據的不正確(包括不同副本的不一致)。爲了解決這個問題,RAID硬件中一般都有一小塊非易失性RAM(可以通過單獨的電池供電實現令RAM不斷電)。上面保存了寫入日誌。在系統從失敗中恢復後,根據保存的寫入日誌可以繼續寫操作,直到數據重新變得一致。

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

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