Buffer Cache的記憶體結構

renjixinchina發表於2013-07-29

Buffer Cache概述

Buffer CacheSGA的一部分,Oracle利用Buffer Cache來管理data blockBuffer Cache的最終目的就是儘可能的減少磁碟I/O

buffer cache所能提供的功能主要包括:

透過快取資料塊,從而減少I/O

透過構造CRConsistent Read)塊,從而提供讀一致性功能。

透過提供各種locklatch機制,從而提供多個程式併發訪問同一個資料塊的功能。

 

記憶體裡的資料塊通常叫做buffer,而資料檔案裡的資料塊通常叫做block,二者是一個意思。一般我們會混用這兩個名詞。

Buffer Cache 中的管理結構

Buffer Cache中主要有3大結構用來管理Buffer Cache

            1Hash Bucket  Hash Chain List Hash BucketHash Chain List用來實現data block的快速定位。

 

buffer cache就像一個水池,水池的最小單位就是資料塊。當每個資料塊被讀入buffer cache時,Oracle都會抽取資料塊的頭部,在記憶體中構建buffer header,並將這些buffer header串成連結串列的形式。而buffer header裡面記錄的指標就指向buffer cache中的該資料塊本身。於是,Oracle在搜尋某個資料塊時,就不用去buffer cache中找,而是直接掃描連結串列上該資料塊所對應的buffer header,然後根據找到的buffer header所記錄的指標就能到buffer cache中直接定位該資料塊了。

 

在管理buffer header的過程中,Oracle同樣藉助了hash演算法。透過對buffer header裡記錄的資料塊地址和資料塊型別運用hash函式以後,得到該資料塊所屬的組號。

 

這裡的hash chain就是屬於同一個hash bucket的所有buffer header所串起來的連結串列。實際上,hash bucket只是一個邏輯上的概念。每個hash bucket都是透過不同的hash chain體現出來的。每個hash chain都會由一個cache buffers chains latch來管理其併發操作。

 

啟動資料庫以後,Oracle究竟產生多少個hash bucket,則由Oracle自己計算。

 

當前臺程式發出SELECT或者其他DML語句時,Oracle根據SQL語句的執行計劃找到符合SQL條件的資料塊,然後Oracle會根據對請求的資料塊的地址以及資料塊的型別作為引數,應用hash函式以後,得到要找的資料塊所處的hash bucket,也就是確定該資料塊在哪條hash chain上。然後,Oracle進入該hash chain,從上面所掛的第一個buffer header開始,根據buffer header所含有的指標找到對應的塊體,然後掃描其中的資料,確認其是否是SQL語句所需要的塊,如果是,則返回該塊裡所需要的資料;否則,如果不是,則繼續往下搜尋,一直搜尋到最後一個buffer header為止。如果一直都沒有找到,則呼叫物理I/O,到資料檔案裡把該塊所含有的內容複製一份到一個可用的buffer裡,並構建該塊的buffer header,然後將該buffer header掛到hash chain上去。

 

            2LRU List :掛載有指向具體的free buffer, pinned buffer以及還沒有被移動到 write listdirty buffer 等資訊。所謂的free buffer就是指沒有包含任何資料的buffer,所謂的pinned buffer,就是指當前正在被訪問的buffer

 

在前面,我們已經知道了Oracle是如何在hash chain中搜尋要找的資料塊所對應的buffer header的過程,我們也知道如果在hash chain上沒有找到所要的buffer header時,Oracle會發出I/O呼叫,到磁碟上的資料檔案中獲取資料塊,並將該資料塊的內容複製一份到buffer cache中的記憶體資料塊裡。這個時候,假如buffer cache是空的,比較好辦,直接拿一個空的記憶體資料塊來用即可。但是如果buffer cache中的記憶體資料塊全都被用掉了,沒有空的記憶體資料塊了,怎麼辦?應該重新使用哪一個記憶體資料塊?當然我們可以逐個比較記憶體資料塊與其對應在資料檔案中的資料塊的內容是否一致,如果一致則可以將該資料塊拿來,將其內容清空,然後將當前資料塊的內容複製進入;如果不一致,則說明資料塊在記憶體裡被修改了,但是還沒有寫入資料檔案,因此該資料塊不能被其他內容覆蓋,則跳過,再找下一個。毫無疑問,這種方式效率低下。為了高效地管理buffer cache中的記憶體資料塊,Oracle引入了LRU連結串列等結構。

 

buffer cache中,最耳熟能詳的連結串列可能就是LRU連結串列了。在介紹LRU前,先說明幾個概念。

 

 

髒資料塊(dirty buffer):buffer cache中的記憶體資料塊的內容被修改,從而導致與資料檔案中的資料塊的內容不一致。

空閒資料塊(free buffer):buffer cache中的記憶體資料塊為空。

乾淨資料塊(clean buffer):buffer的內容與資料檔案中的一致。

釘住的資料塊(pin buffer):當前正在更新的記憶體資料塊。

資料庫寫程式(DBWR):這是一個很底層的資料庫後臺程式。既然是後臺程式,就表示該程式是不能被使用者呼叫的。由Oracle內建的一些事件根據需要啟動該程式,該程式用來將髒資料塊寫入磁碟上的資料檔案。

 

對於空閒資料塊和乾淨資料塊,我們一般都統稱為可用資料塊,因為其中的內容可以被新的資料內容覆蓋。其他狀態的資料塊,比如髒資料塊,則不能被新的內容覆蓋。

 

LRU表示Least Recently Used,也就是指最近最少使用的buffer header連結串列。LRU連結串列串聯起來的buffer header都指向可用資料塊。buffer按照被使用的先後順序掛在LRU連結串列上,先被使用的buffer掛在LRU連結串列的後面,後被使用的buffer則被掛在LRU連結串列的前面。如果bufferDML語句修改了,則該buffer會從LRU連結串列上摘下來。換句話說,LRU連結串列上的buffer header所指向的buffer都是可用資料塊。

 

當伺服器程式無法找到空的buffer來存放新的資料請求時,則需要把已經存放了資料的buffer拿來使用,也就是用新的資料塊的內容覆蓋曾經使用過的buffer。在查詢應該覆蓋哪個buffer時,Oracle會在LRU連結串列上的尾部開始掃描,如果掃描到的buffer正在被使用,則跳過該buffer,繼續往下找,直到找到為止。如果掃描了一定數量的buffer以後還沒找到可用的buffer,則說明髒塊太多了,於是觸發DBWn程式,將髒塊重新整理到資料檔案裡,重新整理完畢以後,buffer的內容與資料檔案裡的一致,於是這些髒塊就變成乾淨的buffer了,也就可以拿來覆蓋其中的內容了。這些乾淨的buffer就會掛在LRU連結串列的尾部,供程式所使用。

 

當程式在LRU連結串列上掃描可用資料塊時,會受到cache buffers lru chain latch的保護。

            3Write(Dirty)List :掛載有指向具體的 dirty block的資訊。所謂的dirty block,就是指在 buffer cache中被修改過但是還沒有被寫入到磁碟的block

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15747463/viewspace-767374/,如需轉載,請註明出處,否則將追究法律責任。

相關文章