高效能磁碟 I/O 開發學習筆記 — 軟體手段篇

NO IMAGE

上一篇文章我們講了一下硬碟(磁碟 & SSD)在硬體上的一些限制,總結了兩個優化硬碟 I/O 的方向。本篇我們就從 Linux 軟體開發的角度,講一下在軟體設計中我們應該如何提高硬碟 I/O。

本文地址:https://segmentfault.com/a/1190000011830405

這裡,我們會涉及一個新的 “快取” 概念。注意,這裡的 “快取” 和前文所提及的儲存架構中的 “cache” 雖然中英文用詞都一樣,但兩者是不同的。
本文所說的快取,指的是在 Linux 作業系統層面,在應用程式對硬碟進行讀寫(read

改為

ProcessA   ProcessB   ProcessC
|          |          |
|          V          |
*---->  ProcessD  <---*
|
V
The File

順便還可以在這個服務程序中實現一些自己的快取機制,配合 Linux 自身的檔案快取進一步優化磁碟 I/O 效率。

以 4kB 為單位寫檔案

這裡可以看看下面這個虛擬碼:

const int WRITE_BLOCK_SIZE = 4096
for (int i = 0 to 999) {
write(fd, buff, WRITE_BLOCK_SIZE)
}

其實這個問題,就是我在上一篇文章的 “硬碟檔案存取速度的考量” 小節中所說的內容了。
這裡有一個常量 WRITE_BLOCK_SIZE, 這並不是可以隨意取的值,比較合適的是 4096 或者其倍數,理由是檔案系統往往以 4kB 為頁,如果沒有寫夠 4kB 的話,將導致檔案需要多餘的讀出動作。雖然檔案快取在一定程度上能夠幫你緩解,但總會有一部分操作會最落地到底層 I/O 的。所以實際操作中,要儘量以 4kB 為邊界操作大檔案。

大目錄的定址效率

有一個問題被提了出來:我們都知道,當我們面對一個大目錄(目錄中有很多很多檔案)的時候,這個目錄刷出來需要很長的時間。那麼我們在開發的時候是不是要避免經常在這個大目錄中讀寫檔案呢?

實際上,當你第一次操作這個大目錄的時候,可能延時確實會比較大。但是實測只要進入了這個目錄之後,再後續操作的時候,卻一點都不慢,和其他的普通目錄相當。

這個問題的原因,我個人猜測(求權威人士指正)是這樣的:
  目錄在檔案系統中,是以一個 inode 的方式存在的,那麼載入目錄,實際上就是載入這個 inode。從儲存的角度,inode 也只是一個普通的檔案,那麼載入 inode 的動作和載入其他檔案一樣,也會經過檔案快取策略。載入了一次之後,只要你持續地訪問它,那麼作業系統就會將這個 inode 保持在快取中。因此後續的操作,就是直接讀寫 RAM 了,並不會受到硬碟 I/O 瓶頸的影響。

參考資料

Linux 核心的檔案 Cache 管理機制介紹
磁碟I/O那些事
Linux系統結構 詳解
【Linux程式設計基礎】檔案與目錄–知識總結