編者注:在分析完 Linux inode 基礎概念 之後,讓我們看下inode在內存中對應的文件系統抽象VFS,然後分析下關於 磁盤操作 中Page Cache的回寫策略。
VFS(虛擬文件系統層)
VFS是虛擬文件系統層(進程與文件系統之間的抽象層),與它相關的數據結構只存在於物理內存當中。其目的是屏蔽下層具體文件系統操作的差異,為上層的操作提供一個統一接口,正是由於VFS的存在,Linux中允許多個不同的文件系統共存。
VFS中包含著向物理文件系統轉換的一系列數據結構,如VFS超級塊、VFS的Inode、各種操作函數的轉換入口等。Linux中VFS依靠四個主要的數據結構來描述其結構信息,分別為超級塊、索引結點、目錄項和文件對象,這些數據結構大都會與磁盤上的對應上。
由於進程中File對象有獨立的文件偏移量(current file offset),因此多個進程可以讀寫文件的不同位置的數據,但是一般不建議這樣玩,因為系統不保證該情況下的寫的原子性,多進程可以通過文件鎖實現對文件內容的寫保護。
PageCache
Page cache是通過將磁盤中的數據緩存到內存中,從而減少磁盤I/O操作,從而提高性能。此外,還要確保在page cache中的數據更改時能夠被同步到磁盤上,後者被稱為page回寫(page writeback)。一個inode對應一個page cache對象,一個page cache對象包含多個物理page。
當內核發起一個讀請求時(例如進程發起read()請求),首先會檢查請求的數據是否緩存到了page cache中,如果有,那麼直接從內存中讀取,不需要訪問磁盤,這被稱為cache命中(cache hit)。如果cache中沒有請求的數據,即cache未命中(cache miss),就必須從磁盤中讀取數據。然後內核將讀取的數據緩存到cache中,這樣後續的讀請求就可以命中cache了。page可以只緩存一個文件部分的內容,不需要把整個文件都緩存進來。
當內核發起一個寫請求時(例如進程發起write()請求),同樣是直接往cache中寫入,此時不會立即同步到磁盤,而是將寫入的page設置為髒頁,並將其加入dirty list中,內核會負責定期同步到磁盤保持二者一執行。
page cache另一個主要工作是回收page釋放內存空間,此時會選擇合適的page進行釋放,如果是髒頁會先同步到磁盤然後釋放。此時是如何選擇cache頁的呢?Linux使用的策略是基於LRU改進的Two-List策略:
Two-List策略維護了兩個list,active list 和 inactive list。在active list上的page被認為是hot的,不能釋放。只有inactive list上的page可以被釋放的。首次緩存的數據的page會被加入到inactive list中,已經在inactive list中的page如果再次被訪問,就會移入active list中。兩個鏈表都使用了偽LRU算法維護,新的page從尾部加入,移除時從頭部移除,就像隊列一樣。如果active list中page的數量遠大於inactive list,那麼active list頭部的頁面會被移入inactive list中,從而位置兩個表的平衡。
觸發髒頁回寫到磁盤時機如下:
- 用戶進程調用sync() 和 fsync()系統調用;
- 空閒內存低於特定的閾值(threshold);
- Dirty數據在內存中駐留的時間超過一個特定的閾值。
注意這裡的page cache的髒頁回寫機制可以和mmap的髒頁回寫機制做下對比,mmap會在一定時間後系統自動回寫髒頁面到磁盤,也就是說mamp中修改過的髒頁面並不會立即更新迴文件中,而是有一段時間的延遲,可以調用msync()來強制同步, 這樣所寫的內容就能立即保存到文件裡了。
推薦閱讀: