這裡,我們會涉及乙個新的 「快取」 概念。注意,這裡的 「快取」 和前文所提及的儲存架構中的 「cache」 雖然中英文用詞都一樣,但兩者是不同的。
本文所說的快取,指的是在 linux 作業系統層面,在應用程式對硬碟進行讀寫(read
/write
系統呼叫)時,對硬碟資源所做的乙個預載入 / 延寫入的機制。
多年以前有一次面試,我被問了乙個問題:
—— 「你說一說,我們呼叫write()
之後,linux 是怎麼呼叫到底層的?」
我一臉懵逼,第一反應是這個問題太泛了,如果把我所知道的所有東西說出來的話,從頂層軟體過程到底層硬體驅動編寫,我可以講一下午(參見我的工作經歷)。
我只好再問了一句:「這個範疇有點大,請問您能不能具體地問一下呢?」
估計面試官也沒想到我會反問,他只是重複了一下:「你就……把這個過程說一下吧。」
於是乎,我就從系統呼叫的實現原理講起,然而很快就被面試官打斷:「好吧可以了,你回去等訊息吧。」
訊息肯定是沒等到,而我至今也沒把握面試官希望聽到的答案是什麼。這次說到硬碟 i/o 的時候我忽然想到:或許面試官要的是這個吧? ————
在現代作業系統中,乙個 「真正的」 檔案,當呼叫read
/write
的時候,資料當然不會簡單地就直達硬碟。對於 linux 而言,這個過程的一部分是這樣的:
在作業系統核心空間內,read / write 到硬體裝置之間,按順序有這麼幾層:
這裡我覺得 ibm 的資料講的特別清楚。下面是重點摘抄:
當應用程式需要讀取檔案中的資料時,作業系統先分配一些記憶體,將資料從儲存裝置讀入到這些記憶體中,然後再將資料分發給應用程式;當需要往檔案中寫資料時,作業系統先分配記憶體接收使用者資料,然後再將資料從記憶體寫到磁碟上。
對於每個檔案的第乙個讀請求,系統讀入所請求的頁面並讀入緊隨其後的少數幾個頁面(不少於乙個頁面,通常是三個頁面),這時的預讀稱為同步預讀。
如果應用程式接下來是順序讀取的話,那麼檔案 cache 命中,os 會加大同步預讀的範圍,增強快取效率,此時的預讀被稱為非同步預讀
如果接下來 cache 沒命中,那麼 os 會繼續使用同步預讀。
知道了原理之後,接下來就是怎麼做的問題了——
從快取的工作機制來看,很簡單,如果要充分利用 linux 的檔案快取機制,那麼最好的方法就是:每乙個檔案都盡可能地採用順序讀寫,避免大量的seek
呼叫。
從檔案快取角度,如果頻繁地隨機讀取乙個檔案不同的位置,很可能導致快取命中率下降。那麼 os 就不得不頻繁地往硬碟上預讀,進一步導致硬碟利用率低下。所以在讀寫檔案的時候,盡可能的只是簡單寫入或者簡單讀取檔案,而不要使用seek
。
這條原則非常適用於 log 檔案的寫入:當寫入 log 的時候,寫就好了,不要經常翻回去檢視以前的內容。
整個系統,最好只有乙個程序進行磁碟的讀寫。而不是多個程序進行檔案訪問。這個思路,一方面和上一條 「順序寫」 原則的理由其實是一致的。當多個程序進行磁碟讀寫的時候,隨機度瞬間飆公升。特別是多個程序操作多個檔案的時候,磁碟的磁頭很可能需要頻繁大範圍地移動。
如果確實有必要多個程序分別讀取多個不同檔案的話,可以考慮下面的替代方案:
如果是多個程序同時寫入乙個檔案(比如 log),那就更好辦了。這種情況下,可以在這幾個程序和檔案中間加入乙個內部檔案伺服器,將所有程序的訪問檔案需求彙總到該檔案伺服器中進行統一處理。
processa processb processc
| | |
| v |
*----> the file
改為
processa processb processc
| | |
| v |
*----> processd |v
the file
順便還可以在這個服務程序中實現一些自己的快取機制,配合 linux 自身的檔案快取進一步優化磁碟 i/o 效率。
以 4kb 為單位寫檔案
這裡可以看看下面這個偽**:
const int write_block_size = 4096
for (int i = 0 to 999)
有乙個問題被提了出來:我們都知道,當我們面對乙個大目錄(目錄中有很多很多檔案)的時候,這個目錄刷出來需要很長的時間。那麼我們在開發的時候是不是要避免經常在這個大目錄中讀寫檔案呢?
實際上,當你第一次操作這個大目錄的時候,可能延時確實會比較大。但是實測只要進入了這個目錄之後,再後續操作的時候,卻一點都不慢,和其他的普通目錄相當。
這個問題的原因,我個人猜測(求權威人士指正)是這樣的:
目錄在檔案系統中,是以乙個inode的方式存在的,那麼載入目錄,實際上就是載入這個 inode。從儲存的角度,inode 也只是乙個普通的檔案,那麼載入 inode 的動作和載入其他檔案一樣,也會經過檔案快取策略。載入了一次之後,只要你持續地訪問它,那麼作業系統就會將這個 inode 保持在快取中。因此後續的操作,就是直接讀寫 ram 了,並不會受到硬碟 i/o 瓶頸的影響。
linux 核心的檔案 cache 管理機制介紹
磁碟i/o那些事
linux系統結構 詳解
【linux程式設計基礎】檔案與目錄--知識總結
高效能mysql學習筆記
此文已由作者朱笑天授權網易雲社群發布。筆者在工作之餘閱讀了一下高效能mysql,以下的內容對mysql的介紹以及書中涉及一些概念的總結歸納。1.mysql架構 1.最上層負責鏈結處理 認證授權 安全等 2.中間一層涵蓋了mysql的大多數核心功能。包括查詢解析 分析 優化 快取 內建函式 所有的誇儲...
python學習筆記 提高效能
keep code not data 減少 能減少生成的 因此能減少執行時間 python是解釋執行的,量少對效能確實有好處,針對被呼叫次數高的 可以使用一些技巧減少 行獲得效能的提公升。有些函式會被呼叫成千上萬次,每次執行的時間從0.005優化到0.0025也是很了不起的。使用list compr...
高效能 架構例項 學習筆記
web應用的效能優化思路 找到瓶頸 百萬級訪問量 的技術準備工作 youtube 架構學習體會 idea 優酷網的架構學習筆記 百萬級php 架構工具箱 回顧myspace架構的坎坷之路 wikipedia技術架構學習筆記 flickr 架構分析 idea 一步步構建大型 架構 facebook儲存...