曾經作嵌入式開發的我,如今作服務器開發,不少思路要轉變。今天學習了服務器高性能IO設計,同時本身也還發散開去學習了其餘的一些參考資料,順便結合本身已有的一些知識,作爲本身的學習筆記,總結和記錄一下吧~~html
本文首先從硬件原理的角度,闡述提升硬盤 I/O 效率的途徑。
本文包括一些小知識,與高性能服務器開發沒有直接關係,不感興趣的話能夠跳過。segmentfault
本文地址:http://www.javashuo.com/article/p-aadigvbs-hr.html緩存
這裏我所說的 「硬盤」,也就是所謂的 「hard disk」,常常簡稱爲 「disk」 或者 「HDD」,同時還有另一個更加高大上的名字 「非易失性存儲」。安全
請各位回憶一下計算機組成原理裏關於存儲的部分,從 CPU 開始,存儲層次以下:服務器
非易失性存儲就是說該存儲介質上的數據,只要寫入了,那麼就算設備掉電了,也可以保持,而不會被清空。
廣義而言,非易失性存儲包含很是多的種類,包括磁盤、閃存、EEPROM 等等。而對於服務器而言,只涉及兩種,那就是磁盤和 SSD。網絡
磁盤使用磁性元件作成盤片,而後使用盤片上對應位置是否有磁性,來判斷該位置存儲的值是邏輯 1 仍是邏輯 0。
另外一種是固態硬盤,也就是 SSD。SSD 的原理其實就是咱們的 「U盤」。從存儲介質的角度,「U盤」 其實不是一個準確的說法,準確的說,應該叫作 「閃存」(flash memory)。oop
從製造原理上,閃存又分爲兩種,一種是 NOR-flash,另外一種是 NAND-Flash。NOR-Flash 不會在服務器上使用,正文略過不講(感興趣的話,能夠看本文的小知識)。本文關注的是使用 NAND-Flash 製做而成的硬盤,也就是 SSD。性能
Linux 中,全部的東西均可以抽象成文件。而全部的設備,則會被分爲字符設備和塊設備。
字符設備的意思是,對於該設備上隨機指定的地址的值,均可以直接寫入。學習
相對應地,塊設備的意思是,對於該設備上隨機指定的地址上的數據,若是須要修改的話,須要連同該地址周邊一整塊數據都一塊兒讀到內存中、修改了指定數據以後,再整塊寫回。優化
<<<< 小知識:爲何 SSD 是塊設備?爲何寫入這麼麻煩?>>>> SSD 不能簡單隨機地讀寫給定地址上的數據。SSD 讀取以 」頁「 爲單位(如:256 Bytes),擦除 / 寫入以 」塊「 (與內存映射的 「4kB」 的那個 「塊」 不是一回事) 爲單位。 此外,SSD 還有一個很大的特色,就是修改對應數據的時候,還不是簡單地執行一個 write 動做 (不是標準 C 的 write())就能夠了,而是須要首先執行一次 erase 操做,將當前的整個塊擦除掉 (所有變成邏輯 0),而後再將整個塊的數據從新寫一遍。 因此對於塊設備而言,執行讀操做還算簡單,可是執行寫操做的話,整個流程就變成了:read、erase、 write 了,何其複雜!SSD 之因此被設計成這麼複雜的緣由,主要是半導體比特密度和制形成本之間的一個 取捨。原理能夠寫一整章,本文就不展開講了。 爲何磁盤是塊設備?這個很抱歉,筆者沒有準確的答案。或許由於磁盤轉的太快,沒辦法極其精 準地定位具體一個 bit?
這裏咱們先放下 SSD,來說一講磁盤。我的電腦和服務器上所使用的磁盤結構都是如出一轍的。磁盤的結構和各術語以下圖所示:
磁盤中會並列地擺放不少片盤片,每一個盤片的正反面都會有一個磁頭,使用這個磁頭來讀取盤片上的磁狀態。讀數據的時候,通常會同時從幾個盤片讀,以達到最高的讀取速度。
因此咱們能夠看到,磁盤尋址的速度,主要受到如下兩個因素的影響:
極端狀況下,磁頭須要從一端轉到另外一端;而盤片則須要轉動 180 度。
乍一看,其實這兩個時間是很是短的,彷佛並不會影響讀取文件的速度。兩邊引發質變,這兩個時間積累起來的時候,就會出現問題了。那麼怎樣才能累積呢?答案就是:頻繁、隨機地存取文件系統。
因此,提升磁盤效率的思路就是:避免頻繁的隨機存取文件
這裏所說的包含磁盤和 SSD。前面已經說了,硬盤是塊設備,也就是當讀取內容的時候,只能以塊爲單位進行操做。
這裏舉一個最簡單的例子吧,咱們把塊的單位減小到 8bits,存取的單位以 bits 來計算。好比在一段連續的內存中,數據是這樣的:
Addr: 0 1 2 3 4 5 6 7 value: 0 0 1 1 0 1 0 0
咱們只須要讀取地址 5 上的值,這就是所謂的隨機讀取。可是硬盤的原理決定了咱們沒辦法只讀這麼一個數據。驅動只能把這一整塊的數據(00110100)一塊兒讀出來,而後再把這地址 5 的值返回給應用程序。
寫入的時候就更復雜了。針對 SSD,若是咱們須要把地址 5 上的值改成 0,那麼驅動須要幹下面幾件事情:
磁盤還算比較簡單,只須要執行 1 和 4 兩個步驟就好了。
從上面的流程咱們大概能夠看到磁盤文件存取速度的優化方向了。若是你還沒弄明白的話,我再舉一個例子:
假設仍是上面的多個 SSD 塊,咱們作一次循環操做來模擬屢次存取。僞代碼以下:
define SECT_SIZE (5) int addr = 0; for (sectNum = 0 to 100) { bits[SECT_SIZE] = read_data(from: addr, len: SECT_SIZE); bits[0] = 0; bits[SECT_SIZE - 1] = 0; // 只修改一部分 write_data(data: bits, from: addr, len: SECT_SIZE) addr += SECT_SIZE }
這段代碼有什麼問題呢?咱們只須要取前兩次循環,看看驅動作了什事情就知道了。
首先是第一次循環(Loop 0):
此時 addr = 0, 1. 從 0 號塊讀出 8 bits 的數據,而且取其中的 5bits 返回給應用程序(耗時 t1) 2. 應用程序修改了兩個 bits 3. 將 0 號塊的 8bits 寫回(擦除 + 寫入,耗時 t2)
第二次循環就不同了:
此時 addr = 5 1. 從 0 號塊取出 8bits 的數據,而且取最後 3bits 爲有效數據(耗時 t1) 2. 從 1 號塊取出 8bits 的數據,而且取前 2bits 爲有效數據,與前面的 3bits 拼在一塊兒,返回 5bits 給應用程序(耗時 t1) 3. 應用程序修改了兩個 bits 4. 將 0 號塊的 8bits 寫回(耗時 t2) 5. 將 1 號塊的 8bits 寫回(耗時 t2) 總耗時是第一個循環的兩倍。
可見,因爲橫跨了兩個塊,雖然應用程序操做的數據量是同樣的,可是操做的時間卻多出了整整一倍。
所以從這裏咱們能夠看出,提升硬盤存取效率的另外一個途徑是:儘量以塊爲單位,進行讀寫操做。在操做系統中,軟件層面關心的塊的單位通常是 4096 字節(4kB)。
一句話,NOR Flash 只用在嵌入式設備中,作服務器開發的不須要關心。本小節沒有正片,只有小知識。
<<<< 小知識:NOR Flash 是什麼?有什麼特色? >>>> NOR Flash 和本文所說的 SDD(NAND Flash)的區別,首先在硬件結構上顯然是不一樣的。可是嘛, 如前文所述,硬件的咱不講。 NOR Flash 的特色有下面幾點: 1. NOR Flash 也是塊設備,但 NOR Flash 支持絕對的隨機讀取,要讀多長就讀多長,而且讀取 速度高於 NAND Flash 2. 相同條件下,NOR Flash 的擦除和寫入耗時遠遠大於 NAND Flash 3. NOR Flash 支持有限的隨機寫能力,所謂有限,意思是 NOR Flash 能夠將任意邏輯 0 的位改 寫爲邏輯 1,可是卻沒辦法將 1 改寫爲 0 4. NOR 執行塊的擦除操做後,整個塊都會變成邏輯 0。所以對於絕大部分數據(0 和 1 混雜的) 寫入操做,實際上和 NAND Flash 的操做流程是同樣的 5. 當容量小於 16MB 時,NOR Flash 的成本小於 NAND Flash。再往上就不如 NAND 了。 上面的特性,使得 NOR Flash 幾乎不會用在 PC 的存儲體系中。但卻在嵌入式設備中(包括計算 機主板上 BIOS 的存儲器)應用極廣,由於: 1. 嵌入式設備主要是保存大量的代碼數據(只讀,特色1),和少數而且不多變更的用戶數據(讀寫, 特色1) 2. 嵌入式設備的程序空間很小,裁減過的 Linux 內核通過壓縮能夠達到2MB 甚至更低(特色5) 3. 嵌入式設備可能隨時斷電,支持 jffs2 文件系統以後,能夠保護文件內容(特色3)
<<<< 小知識:爲何支持了 jffs2 就支持斷電保護?>>>> 能夠說 jffs2 簡直就是爲 NOR Flash 量身定作的文件系統了。通常而言,好比咱們使用 FAT32 對 U盤進行格式化以後,若是 U盤在寫入數據的時候忽然從主機設備上拔掉,那麼文件系統極可能會崩 潰、損壞。這就是爲何操做系統會有 「安全移除存儲設備」 的功能。 Jffs2 完美地利用了 NOR Flash 「能夠將 0 改寫爲 1」 的特性。首先在格式化的時候,jffs2 以 塊爲單位劃分存儲空間,而後在建立索引表的時候。文件系統在將數據寫完以前,會對應的塊設置爲 0, 也就是標記爲無效塊。當數據徹底寫入完成以後,就將標記從 0 修改成 1。而 jffs2 每次加載的時候, 會遍歷全部的塊,而且在內存中重建索引表。 若是在寫入數據的過程當中斷電了,那麼相應的塊繼續保持無效狀態。這樣就保證了文件系統的斷電 保護。 固然 jffs2 的原理遠遠沒有這麼簡單。Linux 裏面就有 jffs2 的代碼,各位看官能夠自行取用。
針對硬盤做爲塊設備的各類特色,從硬件原理上優化磁盤效率,咱們的思路主要就是兩個方向:
實際代碼中具體應該怎麼操做,在下一篇文中給出。