文件系統(tǒng)的緩存管理 2.6 dentry的數(shù)據(jù)結(jié)構(gòu) 3.5 /proc/meminfo中Buffers和Cached的區(qū)別
1 緩存的概念緩存位于客戶和服務(wù)中間,用來加速訪問。 常見的緩存有CPU緩存、瀏覽器緩存、代理服務(wù)器緩存等。
2 dentry緩存和inode緩存2.1
文件名查找
如果想打開/usr/local/bin/xxx,首先要知道xxx的inode,它保存在/usr/local/bin這個目錄文件中,要打開/usr/local/bin這個文件,需要知道/usr/local/bin的inode,它的inode保存在/usr/local這個目錄文件中,依次類推,直至查找“/”的inode。實(shí)際操作中,先打開磁盤中的/目錄文件,查找/usr的inode,然后打開磁盤中的/usr文件,查找/usr/local的inode,依次如此這般。因此文件名查找需要反復(fù)查詢inode表,并打開相應(yīng)的目錄文件讀取inode。 2.2
dentry緩存
在打開文件時,將需要的目錄項(xiàng)都復(fù)制一份到內(nèi)存中,下次需要讀取相同的inode時,通過dentry緩存直接找到對應(yīng)的inode 2.3
dentry緩存的查找方式
dentry的數(shù)據(jù)結(jié)構(gòu)中有d_subdirs鏈表,鏈表元素可以連接到它的子目錄和文件的dentry實(shí)例,搜索時沿著這個鏈表搜索。 2.4
dentry緩存的管理
內(nèi)存中維護(hù)一個散列表(dentry_hashtable)包含了所有的dentry對象,還有一個LRU(最近最少使用,least recently used)鏈表,當(dāng)某個dentry不再被使用時(使用計數(shù)d_count為0),放進(jìn)這個列表。新放進(jìn)LRU的dentry項(xiàng)置于鏈表的起始處,這表明越舊的dentry項(xiàng)就越靠后,在內(nèi)核需要更多內(nèi)存時,就會把一些比較舊的dentry釋放掉。 LRU鏈表中的對象同時也處于散列表中,因此在需要時,也可通過散列表找到它,將其從LRU表中刪除,同時將其使用計數(shù)加1。 2.5
超級塊的dentry緩存
在超級塊的內(nèi)存結(jié)構(gòu)中,包含一個指針s_root,它指向內(nèi)存中一個dentry實(shí)例。因此所有文件系統(tǒng)的根目錄的dentry都在文件系統(tǒng)掛載的同時就加載到內(nèi)存中了,相應(yīng)的inode緩存也必然已經(jīng)加載到內(nèi)存中。 2.6
dentry的數(shù)據(jù)結(jié)構(gòu)
struct
dentry { atomic_t d_count; unsigned int d_flags; /* protected by d_lock */ spinlock_t d_lock; /* per dentry lock */ int d_mounted; struct inode *d_inode; /* Where the name belongs to - NULL is * negative */ /* * The
next three fields are touched by __d_lookup.
Place them here * so
they all fit in a cache line. */ struct hlist_node d_hash; /* lookup hash list */ struct dentry *d_parent; /* parent directory */ struct qstr d_name;
struct list_head d_lru; /* LRU list */ /* * d_child
and d_rcu can share memory */ union { struct list_head d_child; /* child of parent list */ struct rcu_head d_rcu; } d_u; struct list_head d_subdirs; /* our children */ struct list_head d_alias; /* inode alias list */ unsigned long d_time; /* used by d_revalidate
*/ const struct dentry_operations *d_op; struct super_block *d_sb; /* The root of the dentry tree */ void *d_fsdata; /* fs-specific data */
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ };
2.7
inode緩存
將inode的內(nèi)容保存在內(nèi)存中
3 Page和Buffer緩存3.1
緩存的作用
緩存利用一部分系統(tǒng)物理內(nèi)存,確保最重要、最常使用的塊設(shè)備數(shù)據(jù)在操作時可以直接從內(nèi)存中獲取,而無需從低速設(shè)備中讀取 數(shù)據(jù)在每次修改后并非都立即寫回,同樣是保存在寫緩存中,在一定的時間間隔之后在回寫。 3.2
緩存的種類
對低速設(shè)備的緩存有頁緩存和塊緩存兩種。頁緩存以內(nèi)存頁為單位,一般為4K;塊緩存以磁盤塊為單位,在進(jìn)行I/O操作時,存取的單位是設(shè)備的各個塊,而不是整個內(nèi)存頁。 頁緩存占主要地位,因?yàn)閮?nèi)核中其它部分的操作都是以內(nèi)存頁為單位的;在以讀取元數(shù)據(jù)塊時,用塊緩存更加方便。 塊緩存分兩種,一種是頁緩存的附屬,一種是獨(dú)立的塊緩存。 3.3
附屬在頁緩存上的塊緩存
一些與塊設(shè)備之間的傳輸操作,傳輸單位的長度依賴于底層設(shè)備的塊長度,而內(nèi)核的許多部分按頁的粒度來執(zhí)行I/O操作,在這種情況下,塊緩存充當(dāng)了雙方的中介。 一幀頁緩存包含一個或多個塊緩存,數(shù)目取決于塊大小。頁緩存中的塊與塊之間沒有間隙,對塊的管理有單獨(dú)的緩沖頭結(jié)構(gòu)。 每個塊緩存有一個緩沖頭,它包含了與塊緩存狀態(tài)相關(guān)的所有管理數(shù)據(jù),包括塊號、塊長度、訪問計數(shù)器等等。緩沖頭和塊緩存數(shù)據(jù)在內(nèi)存中分屬完全獨(dú)立的不同區(qū)域。 3.4
獨(dú)立的塊緩存
依然保存在頁中,但無需關(guān)注塊在頁中的組織。 采用LRU管理 3.5
/proc/meminfo中Buffers和Cached的區(qū)別
Buffers存儲的是文件的元數(shù)據(jù)塊 Cached存儲的是文件的實(shí)際數(shù)據(jù) 4 數(shù)據(jù)回寫4.1
概念
數(shù)據(jù)總是在物理內(nèi)存中操作,隨后在隨機(jī)的時間點(diǎn)寫回到磁盤,以保存修改。 兩種處理方式:周期性的和強(qiáng)制性的。 內(nèi)存中的超級塊結(jié)構(gòu)中包含了臟塊的鏈表,從這個鏈表中選擇一部分或全部臟塊寫回近磁盤。 4.2
周期性寫回
系統(tǒng)啟動時默認(rèn)啟動2個pdflush線程,并使其處于睡眠狀態(tài)。在系統(tǒng)寫操作并不繁忙時,定期啟動pdflush線程,將一定量的臟頁(默認(rèn)是1024)寫回磁盤,然后進(jìn)入睡眠狀態(tài)。 默認(rèn)情況下,并發(fā)的pdflush線程是2,最大是8.。當(dāng)系統(tǒng)中超過1秒鐘沒有空閑的pdflush線程,則啟動一個新的pdflush。若某個線程的空閑時間超過1秒,則銷毀它,但要保證系統(tǒng)中pdflush線程數(shù)不少于2個。 當(dāng)前并發(fā)的pdflush線程數(shù)可通過/proc/sys/vm/nr_pdflush_threads查看,該參數(shù)只讀不可改。 運(yùn)作機(jī)制簡述: 一個pdflush線程調(diào)用wb_kupdate函數(shù)來回寫,回寫的頁總數(shù)不能超過1024個頁,默認(rèn)只有變臟一段時間的頁才會被回寫,還可以回寫對應(yīng)指定設(shè)備的臟頁。由于回寫需要上鎖,因此具體過程是通過一個循環(huán)來實(shí)現(xiàn),每次回寫一部分,直至所有臟塊寫完或總數(shù)達(dá)到1024,寫完后進(jìn)入睡眠,過一定時間間隔再次被喚醒。 若某個頁被內(nèi)核其它部分鎖定,則默認(rèn)跳過它,下次pdflush啟動時再去回寫。 若一次回寫的時間超過了wb_kupdate線程啟動的時間間隔,則推遲1秒在調(diào)用wb_kupdate。 回寫時在遇到阻塞時,可選擇等待或跳過,在struct writeback_control中設(shè)置sync_mode為WB_SYNC_ALL時,稱作數(shù)據(jù)完整性回寫,在阻塞時等待,直至回寫真正完成。 4.3
完全同步
將系統(tǒng)中所有臟頁全部回寫,用sync系統(tǒng)調(diào)用實(shí)現(xiàn),有一個同名的用戶程序。 4.4
強(qiáng)制寫回
當(dāng)需要更多的空閑內(nèi)存時或來自用戶的sync系統(tǒng)調(diào)用,內(nèi)核啟動強(qiáng)制回寫函數(shù)wakeup_pdflush。 某些強(qiáng)制寫回并不等待回寫完成,而是發(fā)出請求后即返回,除非是數(shù)據(jù)完整性同步。 若某個進(jìn)程產(chǎn)生大量臟頁,會強(qiáng)制這個進(jìn)程調(diào)用回寫函數(shù)balance_dirty_pages(mm/page-writeback.c)。
4.5
當(dāng)今最新進(jìn)展
pdflush在新版內(nèi)核中已經(jīng)被移除。 一個塊設(shè)備上可能有幾個臟塊隊(duì)列,每一個pdflush線程可以處理一個或多個隊(duì)列,但每個塊設(shè)備均有擁塞限制,默認(rèn)是128個寫請求。 原有的pdflush機(jī)制是和設(shè)備數(shù)無關(guān)的,寫回隊(duì)列和超級塊掛鉤,現(xiàn)在內(nèi)核中回寫機(jī)制是和設(shè)備掛鉤的。每個塊設(shè)備均有一個flush線程
5 proc文件系統(tǒng)5.1
概述
proc文件系統(tǒng)是一種虛擬文件系統(tǒng),其信息并沒有存儲在塊設(shè)備上,而是在讀取的時候,才從內(nèi)存中動態(tài)生成內(nèi)容。通過它,用戶可以讀取內(nèi)核數(shù)據(jù),并可以改變某些內(nèi)核數(shù)據(jù),從而改變系統(tǒng)的行為。
5.2
proc中文件的讀寫方法
proc中的文件的文件都是文本文件,可以用cat或less去讀,用echo去寫。需要注意的是,并不是每個文件都可寫,有些是只讀的。
6
通過proc文件系統(tǒng)管理緩存
/proc/sys/vm dirty_background_bytes:緩存中的臟數(shù)據(jù)達(dá)到設(shè)定值時,啟動pdflush開始強(qiáng)制寫回。默認(rèn)值是0,即沒有設(shè)定,其值實(shí)際上是計算得出,dirty_background_ratio *
the amount of dirtyable memory。
dirty_background_ratio:緩存中的臟數(shù)據(jù)達(dá)到設(shè)定的比例時,啟動pdflush開始強(qiáng)制寫回。默認(rèn)值是10。這個比例是指臟數(shù)據(jù)與可用內(nèi)存之比,可用內(nèi)存是指:未使用的內(nèi)存+當(dāng)前可回收的內(nèi)存 (在LRU中活動或非活動的內(nèi)存頁,包括可回收的緩存和映射的內(nèi)存頁)。如果dirty_background_bytes已設(shè)置,則此處的設(shè)置無效,其值根據(jù)dirty_background_bytes重新計算,dirty_background_bytes / the amount of dirtyable system memory。若其值大于dirty_ratio,則自動下降至dirty_ratio的一半。(在mm\page-writeback.c中的get_dirty_limits函數(shù)中計算)
dirty_ratio:某個進(jìn)程產(chǎn)生的臟頁到達(dá)此比例時(默認(rèn)為20%,但不能小于5%),開始強(qiáng)制寫回。此時由于回寫頁數(shù)很多,導(dǎo)致設(shè)備上的寫隊(duì)列擁塞,因此這個設(shè)備上的IO操作會被阻塞,可能導(dǎo)致很多進(jìn)程掛起,從而出現(xiàn)系統(tǒng)停止響應(yīng)的現(xiàn)象。若系統(tǒng)寫負(fù)荷較重,可適當(dāng)降低dirty_background_ratio、dirty_expire_centisecs、dirty_writeback_centisecs等參數(shù),使系統(tǒng)的回寫在時間上盡量分散開。
dirty_bytes:某個進(jìn)程產(chǎn)生的臟頁到達(dá)此字節(jié)數(shù),開始強(qiáng)制寫回。默認(rèn)為0,即禁用,最小值不能少于兩個內(nèi)存頁,否則使用舊設(shè)置的值。此參數(shù)優(yōu)先級高于dirty_ratio,當(dāng)被設(shè)置時,dirty_ratio根據(jù)它計算得出(dirty_bytes / the amount
of dirtyable system memory)。設(shè)置非0數(shù)值后,dirty_ratio變?yōu)?span lang="EN-US">0。設(shè)置dirty_ratio后dirty_bytes變?yōu)?span lang="EN-US">0.
dirty_expire_centisecs:時間值,當(dāng)頁變臟時間超過此值時,pdflush將其寫回。以百分之一秒為單位,默認(rèn)值為3000,即30秒。
dirty_writeback_centisecs:時間值,為pdflush的調(diào)用周期,以百分之一秒為單位,默認(rèn)值為500,即5秒。
drop_caches:用于釋放頁緩存、dentry緩存和inode緩存。值為0時代表禁用;值為1時釋放頁緩存;值為2時釋放dentry和inode緩存;值為3時釋放頁緩存、dentry緩存和inode緩存。注意:它并不能釋放臟塊。
nr_pdflush_threads:當(dāng)前并發(fā)的pdflush線程數(shù),該參數(shù)只讀不可改。
vfs_cache_pressure:用于確定回收dentry緩存和inode緩存的策略,默認(rèn)值是100。小于100表示傾向于保留dentry緩存和inode緩存,意味著盡管有一些緩存已經(jīng)沒有進(jìn)程在使用它,但依然會保留下來,大于100則相反。如果為0則不回收它們,不過這樣容易導(dǎo)致內(nèi)存溢出,即沒有可用內(nèi)存分配給進(jìn)程。
/sys/block/xxx/queue/nr_requests:這個塊設(shè)備讀、寫隊(duì)列發(fā)生擁塞時的請求數(shù)上限,默認(rèn)是128(讀寫都是128),即寫請求數(shù)少于128時,認(rèn)為這個設(shè)備還有能力接受更多的寫請求,pdflush不會遇到阻塞。如果塊設(shè)備性能好,可調(diào)大此參數(shù)。
7 示例運(yùn)行一個遍歷目錄的腳本,通過free命令可以看到buffer在上升,slabtop命令可以看到dentry、ext3_inode_cache都在上升,而cache不變。 停止腳本, echo 1 > /proc/sys/vm/drop_caches,buffer迅速回落,幾乎為0,free命令中的使用的內(nèi)存也減少同樣的數(shù)量;dentry、ext3_inode_cache不變; echo
2 > /proc/sys/vm/drop_caches,dentry、ext3_inode_cache迅速回落,free命令中的使用的內(nèi)存也減少同樣的數(shù)量。 結(jié)論:由于腳本只是遍歷目錄,沒有寫操作(除了向標(biāo)準(zhǔn)輸出寫目錄名稱),因此buffer中都是目錄和inode信息,此信息也寫進(jìn)dentry、ext3_inode_cache,即有兩份相同的拷貝。
8 The Swap CacheWhen
swapping pages out to the swap files, Linux avoids writing pages if it does not
have to. There are times when a page is both in a swap file and in physical
memory. This happens when a page that was swapped out of memory was then
brought back into memory when it was again accessed by a process. So long as
the page in memory is not written to, the copy in the swap file remains valid. Linux
uses the swap cache to track these pages. The swap cache is a list of page
table entries, one per physical page in the system. This is a page table entry
for a swapped out page and describes which swap file the page is being held in
together with its location in the swap file. If a swap cache entry is non-zero,
it represents a page which is being held in a swap file that has not been
modified. If the page is subsequently modified (by being written to), its entry
is removed from the swap cache. When
Linux needs to swap a physical page out to a swap file it consults the swap
cache and, if there is a valid entry for this page, it does not need to write
the page out to the swap file. This is because the page in memory has not been
modified since it was last read from the swap file. The
entries in the swap cache are page table entries for swapped out pages. They
are marked as invalid but contain information which allow Linux to find the
right swap file and the right page within that swap file. |
|
來自: 海漩渦 > 《knowledge》