> 文章圖檔和描述來自參考資料非原創
概述
文章主要講 linux 下的關于 page cache 和 buffer cache 的關系和差別。
在我們進行資料持久化,對檔案内容進行落盤處理時,我們時常會使用fsync操作,該操作會将檔案關聯的髒頁(dirty page)資料(實際檔案内容及中繼資料資訊)一同寫回磁盤。這裡提到的髒頁(dirty page)即為頁緩存(page cache)。
塊緩存(buffer cache),則是核心為了加速對底層存儲媒體的通路速度,而建構的一層緩存。他緩存部分磁盤資料,當有磁盤讀取請求時,會首先檢視塊緩存中是否有對應的資料,如果有的話,則直接将對應資料傳回,進而減少對磁盤的通路。
這裡放出一張圖,這樣可以比較直覺地知道IO操作的具體位置,圖檔出處
buffer cache
這是計算機最底層的讀取的資料塊,我們知道計算機從磁盤中讀出的資料最小機關為塊(block)。關于 Buffer cache 的描述下面來自Linux核心Page Cache和Buffer Cache關系及演化曆史
磁盤的最小資料機關為sector,每次讀寫磁盤都是以sector為機關對磁盤進行操作。sector大小跟具體的磁盤類型有關,有的為512Byte, 有的為4K Bytes。無論使用者是希望讀取1個byte,還是10個byte,最終通路磁盤時,都必須以sector為機關讀取,如果裸讀磁盤,那意味着資料讀取的效率會非常低。同樣,如果使用者希望向磁盤某個位置寫入(更新)1個byte的資料,他也必須整個重新整理一個sector,言下之意,則是在寫入這1個byte之前,我們需要先将該1byte所在的磁盤sector資料全部讀出來,在記憶體中,修改對應的這1個byte資料,然後再将整個修改後的sector資料,一口氣寫入磁盤。為了降低這類低效通路,盡可能的提升磁盤通路性能,核心會在磁盤sector上建構一層緩存,他以sector的整數倍力度機關(block),緩存部分sector資料在記憶體中,當有資料讀取請求時,他能夠直接從記憶體中将對應資料讀出。當有資料寫入時,他可以直接再記憶體中直接更新指定部分的資料,然後再通過異步方式,把更新後的資料寫回到對應磁盤的sector中。這層緩存則是塊緩存Buffer Cache。
page cache
page 是什麼,我們在學邏輯空間的時候講到了,當程序加載到記憶體中的有可能以頁為機關加載進去,或是段頁式加載到記憶體。 是以我們的檔案實際上分割為頁。page cache 以 page 為機關,緩存檔案内容。
buffer cache 和 page cache
下面來自參考文章的表述
從linux-2.6.18的核心源碼來看,Page Cache和Buffer Cache是一個事物的兩種表現:對于一個Page而言,對上,他是某個File的一個Page Cache,而對下,他同樣是一個Device上的一組Buffer Cache。
** 可以看到我們邏輯上的 page cache 對應到底層磁盤是 buffer cache **
File在位址空間上,以4K(page size)為機關進行切分,每一個4k都可能對應到一個page上(這裡可能的含義是指,隻有被緩存的部分,才會對應到page上,沒有緩存的部分,則不會對應),而這個4k的page,就是這個檔案的一個Page Cache。而對于落磁盤的一個檔案而言,最終,這個4k的page cache,還需要映射到一組磁盤block對應的buffer cache上,假設block為1k,那麼每個page cache将對應一組(4個)buffer cache,而每一個buffer cache,則有一個對應的buffer cache與device block映射關系的描述符:buffer_head,這個描述符記錄了這個buffer cache對應的block在磁盤上的具體位置
這個圖什麼意思呢? 多個 buffer 對應一個 page ,是以他們之前的映射關系交由 page descriptor 來維護, 而buffer head 則是真正對應底層裝置的資料了。
兩類緩存的演進曆史
參考資料的共講到了三個階段,分别對應的linux版本為 : linux-0.11, linux-2.2.16, linux-2.4.0, linux-2.4.19, linux-2.6.18。有興趣的可以閱讀參考資料,這裡不再深入源碼級别。
第一階段 : 僅有 Buffer Cache
第二階段 : Buffer Cache 和 Page Cache 并存
Page Cache僅負責其中mmap部分的處理,而Buffer Cache實際上負責所有對磁盤的IO通路。從上面圖中,我們也可看出其中一個問題:write繞過了Page Cache,這裡導緻了一個同步問題。當write發生時,有效資料是在Buffer Cache中,而不是在Page Cache中。這就導緻mmap通路的檔案資料可能存在不一緻問題。為了解決這個問題,所有基于磁盤檔案系統的write,都需要調用update_vm_cache()函數,該操作會修改write相關Buffer Cache對應的Page Cache。從代碼中我們可以看到,上述sysv_file_write中,在調用完copy_from_user之後,會調用update_vm_cache
同樣,正是這樣Page Cache、Buffer Cache分離的設計,導緻基于磁盤的檔案,同一份資料,可能在Page Cache中有一份,而同時,卻還在Buffer Cache中有一份。
第三階段 : Page & Buffer Cache 兩者融合
介于上述Page Cache、Buffer Cache分離設計的弊端,Linux-2.4版本中對Page Cache、Buffer Cache的實作進行了融合,融合後的Buffer Cache不再以獨立的形式存在,Buffer Cache的内容,直接存在于Page Cache中,同時,保留了對Buffer Cache的描述符單元:buffer_head
于是就成了這樣,
mmap
和
read/write
實際都是對
page cache
操作,而
page cache
包含多個buffer cache .
下面這張圖和源碼相關的示意圖,以後閱讀代碼的時候再看吧。
最後參考資料第一篇的作者列出了注意的地方
[注意]:這裡的Page Cache與Buffer Cache的融合,是針對檔案這一層面的Page Cache與Buffer Cache的融合。對于跨層的:File層面的Page Cache和裸裝置Buffer Cache,雖然都統一到了基于Page的實作,但File的Page Cache和該檔案對應的Block在裸裝置層通路的Buffer Cache,這兩個是完全獨立的Page,這種情況下,一個實體磁盤Block上的資料,仍然對應了Linux核心中的兩份Page,一個是通過檔案層通路的File的Page Cache(Page Cache),一個是通過裸裝置層通路的Page Cache(Buffer Cache)。
這裡看的有點繞,按我的了解就是對于 ** 檔案系統的 ** ,在最下層磁盤和上層用戶端中間page cache 和 buffer cache 是融合在一起的,有互相的映射關系, 但是檔案也可以是認為是一堆封裝好的2進制的資料, 那麼通過裸裝置和最下層磁盤中間之間直接就是buffer cache 了 ,而沒有對應的 page cache 。
mmap
我們先來看看沒有mmap 的時候。核心需要從拷貝一份到使用者态空間,然後使用者态修改後再回刷到page cache , 而mmap 就是用了一個映射, 修改的東西直接映射到 page cache 。
mmap 還分 private 和 shared ,下面來自參考文章,有興趣可以看一下
A file mapping may be private or shared. This refers only to updates made to the contents in memory: in a private mapping the updates are not committed to disk or made visible to other processes, whereas in a shared mapping they are. Kernels use the copy on write(複制寫機制) mechanism, enabled by page table entries, to implement private mappings.
linux 的 swap 區
在Linux下,SWAP的作用類似Windows系統下的“虛拟記憶體”。當實體記憶體不足時,拿出部分硬碟空間當SWAP分區(虛拟成記憶體)使用,進而解決記憶體容量不足的情況。當作業系統中運作多個程序,記憶體空間又不足,那麼就隻能把一部分程序換出記憶體,等運作的時候在放進來,這個過程就像 ‘SWAP’
linux 的 free 指令
[root@iZm5e7bivgszquxjh18i39Z ~]# free
total used free shared buff/cache available
Mem: 840992 152224 107432 440 581336 555368
Swap: 0 0 0
看到我們的buff/cache 就是指緩存。
補充
參考資料
- http://lday.me/2019/09/09/0023_linux_page_cache_and_buffer_cache/ (推薦閱讀)
- https://www.cnkirito.moe/mq-million-queue/
- https://www.zhihu.com/question/25105320/answer/181056523
- https://manybutfinite.com/post/page-cache-the-affair-between-memory-and-files/ (推薦閱讀)