當(dāng)你第一次打開一個10MB大小的PPT文件時,可能需要等待5秒鐘,然而,第二次再打開同一個文件時幾乎秒開,這是為什么呢?
當(dāng)你復(fù)制粘貼一個大文件時,進(jìn)度條在開始時進(jìn)展緩慢,但到了后半段突然加速。這又是為什么?
操作系統(tǒng)是如何做到“越用越快”,“越用約順手”的呢?實(shí)際上,這一切都?xì)w功于計(jì)算機(jī)中的一項(xiàng)關(guān)鍵技術(shù)——PageCache。
存儲介質(zhì)的性能鴻溝
計(jì)算機(jī)系統(tǒng)中,不同存儲設(shè)備的速度差異巨大。機(jī)械硬盤與內(nèi)存的讀寫速度能有百倍的差距(這里引用的數(shù)據(jù)相對較遠(yuǎn),比較新的沒找到):

這種差距意味著,直接從磁盤讀取數(shù)據(jù)會極大地影響系統(tǒng)的響應(yīng)速度和用戶體驗(yàn),為了彌補(bǔ)這一鴻溝,操作系統(tǒng)引入了PageCache機(jī)制:

道理和CPU和內(nèi)存之間增加L1、L2、L3 cache一樣,只不過L1、L2、L3 cache實(shí)現(xiàn)在硬件層面——CPU中,而pagecache實(shí)現(xiàn)在軟件層面——操作系統(tǒng)中。
什么是PageCache?
PageCache由物理內(nèi)存中的頁面組成,這些頁面的內(nèi)容對應(yīng)于磁盤上的物理塊:

物理內(nèi)存中的頁面當(dāng)然主要用來裝入運(yùn)行的進(jìn)程,剩下的空閑內(nèi)存用來當(dāng)做PageCache:

因此pagecache的大小是動態(tài)的,它可以增長以占用任何空閑內(nèi)存:

也可以縮小以緩解內(nèi)存壓力:

文件讀取
當(dāng)一個進(jìn)程發(fā)起read 系統(tǒng)調(diào)用時,內(nèi)核會首先檢查所需的數(shù)據(jù)是否在頁面緩存中。如果在緩存中,內(nèi)核可以跳過訪問磁盤,直接從內(nèi)存中讀取數(shù)據(jù),這稱為緩存命中(cache hit):

如果數(shù)據(jù)不在pagecache中,稱為緩存未命中(cache miss),此時內(nèi)核必須發(fā)起磁盤I/O 操作,從磁盤讀取數(shù)據(jù)。數(shù)據(jù)從磁盤讀取后,內(nèi)核將數(shù)據(jù)填充到頁面緩存中,以便任何后續(xù)的讀取操作都能直接從緩存中進(jìn)行。
并不是整個文件都需要被緩存,頁面緩存可以將A文件完整緩存,而只緩存B文件的一個或兩個頁面,緩存什么取決于被訪問的內(nèi)容,假設(shè)某個文件有4頁,但經(jīng)常被使用的是第1號頁,那么pagecache中可能就只有這一頁:

這解釋了為什么第一次打開一個10MB大小的PPT文件時,可能需要等待5秒鐘,然而,第二次再打開同一個文件時幾乎秒開,因?yàn)榈谝淮未蜷_PPT后整體PPT是通過磁盤IO加載到內(nèi)存的,而第二次訪問PPT將命中pagecache,如果全部命令那么這將會純內(nèi)存操作,當(dāng)然能做到秒開。
文件寫
當(dāng)一個進(jìn)程通過write系統(tǒng)調(diào)用寫入磁盤時,會發(fā)生什么呢?
操作系統(tǒng)通常采用write-through策略,內(nèi)核將進(jìn)程的寫操作直接寫入pagecache而不會立刻同步更新磁盤,因此在這種策略下文件寫也是純內(nèi)存操作,速度非常快,進(jìn)程不會被阻塞:

復(fù)制粘貼大文件時數(shù)據(jù)需從磁盤先加載到PageCache,受限于磁盤順序讀取速度進(jìn)度條增長緩慢,此時復(fù)制速度取決于磁盤讀取性能。當(dāng)文件數(shù)據(jù)已完全加載到 PageCache 后,后續(xù)讀取直接從內(nèi)存完成。
寫數(shù)據(jù)時數(shù)據(jù)會暫存于內(nèi)存,進(jìn)度條反映的是寫入PageCache的完成度,而非實(shí)際落盤進(jìn)度,此時寫速度從磁盤 I/O 提升到內(nèi)存訪問速度,進(jìn)度條會突然加速。
待更新到磁盤的頁會被內(nèi)核標(biāo)記,然后內(nèi)核周期性地將這些頁面異步寫回磁盤,將內(nèi)存中的緩存與磁盤的數(shù)據(jù)進(jìn)行同步:

當(dāng)然,除了基本的讀寫流程外,PageCache還包含了一些關(guān)鍵機(jī)制來進(jìn)一步優(yōu)化性能。例如,預(yù)讀(Read-ahead)技術(shù)能夠預(yù)測性地加載后續(xù)的數(shù)據(jù)塊,使得順序讀取大文件時效率更高。此外,為了管理有限的內(nèi)存資源,PageCache采用了LRU(最近最少使用)算法來進(jìn)行緩存替換決策。
PageCache帶來了顯著的性能優(yōu)勢,尤其是在重復(fù)訪問同一文件或順序讀取大文件時表現(xiàn)尤為突出。比如在編譯代碼、頻繁讀取配置文件、視頻編輯及處理數(shù)據(jù)庫日志等場景下,PageCache都能發(fā)揮重要作用。
實(shí)驗(yàn)驗(yàn)證
接下來在一臺Linux機(jī)器上驗(yàn)證一下pagecache,首先創(chuàng)建一個大小為1G、內(nèi)容為隨機(jī)數(shù)的文件:
dd if=/dev/urandom of=testfile bs=1M count=1024
然后清空系統(tǒng)中所有的pagecache,可以使用這個命令:
sync && echo 1 > /proc/sys/vm/drop_caches
接著我們讀取一下剛創(chuàng)建的這個文件,并統(tǒng)計(jì)完全讀取整個文件需要的時間,由于在讀取文件之前清空了所有pagecache,因此讀取testfile文件時將觸發(fā)磁盤IO:
$ time cat testfile > /dev/null real 0m6.176s user 0m0.028s sys 0m0.731s
這里輸出的含義是:
?real (實(shí)際時間): 總共經(jīng)過的時間,包括所有等待時間(如I/O等待)。
?user (用戶CPU時間): 程序在用戶模式下執(zhí)行所花費(fèi)的時間。
?sys (系統(tǒng)CPU時間): 程序在內(nèi)核模式下執(zhí)行所花費(fèi)的時間。
可以看到,讀取這1個G的文件總耗時達(dá)到了6.1s左右,因?yàn)檫@涉及磁盤IO,因此讀取速度緩慢,讀完后這個文件將被放到pagecache,接著我們再讀一次:
$ time cat testfile > /dev/null real 0m0.309s user 0m0.011s sys 0m0.298s
可以看到,這次讀取文件只用了0.3s,相差了接近20倍,就是因?yàn)榈诙巫x取幾乎是純內(nèi)存操作。
現(xiàn)在你應(yīng)該明白pagecache的作用了吧。
作者:島主小風(fēng)哥
來源:碼農(nóng)的荒島求生
編輯:小咕咕
轉(zhuǎn)載內(nèi)容僅代表作者觀點(diǎn)
不代表中科院物理所立場
如需轉(zhuǎn)載請聯(lián)系原公眾號
1.2.
3.
4.
5.
6.
7.
8.
9.
10.
熱門跟貼