深入理解Oracle中的latch

zhaokonglei發表於2014-07-10

序列化 概述

序列化 - 資料庫系統本身是一個多使用者併發處理系統,在同一個時間點上,可能會有多個使用者同時運算元據庫, 多個使用者同時在相同的物理位置上寫資料時,不能發生互相覆蓋的情況,這叫做序列化,序列化會降低系統的併發性,但這對於保護資料結構不被破壞來說則是必需的。

Oracle資料庫中,透過閂鎖(latch)和鎖定(lock)來解決這兩個問題。

閂鎖和鎖定既有相同點又有不同點。相同點在於它們都是用於實現序列化的資源。而不同點則在於閂鎖(Latch)是一個低階別、輕量級的鎖,獲得和釋放的速度很快,以類似於訊號燈的方式實現。而鎖定(Lock)則可能持續的時間很長,透過使用佇列,按照先進先出的方式實現。也可以簡單地理解為閂鎖是微觀領域的,而鎖定則是宏觀領域的。

注意 :latch是用於保護SGA區中共享資料結構的一種序列化鎖定機制。它不僅僅用於buffer cache, 還用於shared pool以及log buffer等。

閂鎖(latch )概述

Oracle資料庫使用閂鎖(latch)來管理SGA記憶體的分配和釋放.

Latch是用於保護SGA區中共享資料結構的一種序列化鎖定機制。Latch的實現是與作業系統相關的,尤其和一個程式是否需要等待一個latch、需要等待多長時間有關。

Latch是一種能夠極快地被獲取和釋放的鎖,它通常用於保護描述buffer cacheblock的資料結構。與每個latch相聯絡的還有一個清除過程,當持有latch的程式成為死程式時,該清除過程就會被呼叫。Latch還具有相關級別,用於防止死鎖,一旦一個程式在某個級別上得到一個latch,它就不可能再獲得等同或低於該級別的latch

Latch 不會造成阻塞,只會導致等待。 阻塞是一種系統設計上的問題,等待是一種系統資源爭用的問題。

SPIN與休眠

SPIN

performance tuningsgtuning contention章裡看到的,原文是這樣的:

Latch behavior differs on single and multiple CPU servers. On a single CPU server, a process requesting an in-use latch will release the CPU and sleep before trying the latch again. On multiple CPU servers, a process requesting an in-use latch will “spin” on the CPU a specific number of times before releasing the CPU and trying again. The number of spins the process will use is OS specific.

spin 就是一個程式獨佔cpu time,直到執行的結束。這個期間其他程式不能獲得這個cpu的執行時間。對於單CPU來說沒有spin概念。

比如資料快取中的某個塊要被讀取,我們會獲得這個塊的 latch,這個過程叫做spin,另外一個程式恰好要修改這個塊,他也要spin這個塊,此時他必須等待,當前一個程式釋放latch後才能spin住,然後修改,如果多個程式同時請求的話,他們之間將出現競爭,沒有一個入隊機制,一旦前面程式釋放所定,後面的程式就蜂擁而上,沒有先來後到的概念,並且這一切都發生的非常快,因為Latch的特點是快而短暫。

休眠

休眠意味著暫時的放棄CPU,進行上下文切換(context switch),這樣CPU要儲存當前程式執行時的一些狀態資訊,比如堆疊,訊號量等資料結構,然後引入後續程式的狀態資訊,處理完後再切換回原來的程式狀態,這個過程如果頻繁的發生在一個高事務,高併發程式的處理系統裡面,將是個很昂貴的資源消耗,所以Oracle選擇了spin,讓程式繼續佔有CPU,執行一些空指令,之後繼續請求,繼續spin,直到達到_spin_count值,這時會放棄CPU,進行短暫的休眠,再繼續剛才的動作。初始狀態下,一個程式會睡眠0.01秒。然後醒過來,並再次嘗試獲得latch。 程式一旦進入睡眠狀態,則會丟擲一個對應的等待事件,並記錄在檢視v$session_wait裡,說明當前該程式正在等待的latch的型別等資訊。

Latch的種類

願意等待(Willing-To-Wait)

大部分的latch都屬於這種型別(Willing-To-Wait)。這種型別的latch都是透過Test-And-Set的方式來實現的。

任何時候,只有一個程式可以訪問記憶體中的某一個資料塊,如果程式因為別的程式正佔用塊而無法獲得Latch時,他會對CPU進行一次spin(旋轉),時間非常的短暫,spin過後繼續獲取,不成功仍然spin,直到spin次數到達閥值限制(這個由隱含引數_spin_count指定),此時程式會停止spin,進行短期的休眠,休眠過後會繼續剛才的動作,直到獲取塊上的Latch為止。程式休眠的時間也是存在演算法的,他會隨著spin次數而遞增,以釐秒為單位,如11224488,。。。休眠的閥值限制由隱含引數_max_exponential_sleep控制,預設是2秒,如果當前程式已經佔用了別的Latch,則他的休眠時間不會太長(過長會引起別的程式的Latch等待),此時的休眠最大時間有隱含引數_max_sleep_holding_latch決定,預設是4釐秒。這種時間限制的休眠又稱為短期等待。

另外一種情況是長期等待鎖存器(Latch Wait Posting),此時等待程式請求Latch不成功,進入休眠,他會向鎖存器等待連結串列(Latch Wait List)壓入一條訊號,表示獲取Latch的請求,當佔用程式釋放Latch時會檢查Latch Wait List,向請求的程式傳遞一個訊號,啟用休眠的程式。Latch Wait List是在SGA區維護的一個程式列表,他也需要Latch來保證其正常執行,預設情況下share pool latchlibrary cache latch是採用這個機制。

如果將隱含引數_latch_wait_posting設定為2,則所有Latch都採用這種等待方式,使用這種方式能夠比較精確的喚醒某個等待的程式,但維護Latch Wait List需要系統資源,並且對Latch Wait ListLatch的競爭也可能出現瓶頸。

如果一個程式請求,旋轉,休眠Latch用了很長時間,他會通知PMON程式,檢視Latch的佔用程式是否已經意外終止或死亡,如果是則PMON會清除釋放佔用的Latch資源。

總之, Latch獲取的流程:請求-SPIN-休眠-請求-SPIN-休眠 ... ... 佔用。

不等待(No-Wait

這種型別的latch比較少,對於這種型別的latch來說,都會有很多個可用的latch。當一個程式請求其中的一個latch時,會以no-wait模式開始請求。如果所請求的latch不可用,則程式不會等待,而是立刻請求另外一個latch。只有當所有的latch都不能獲得時,才會進入等待。

latch的獲取過程可以用下圖來概括

 

LatchLock的區別

Latch是對記憶體資料結構提供互斥訪問的一種機制,而Lock是以不同的模式來套取共享資源物件,各個模式間存在著相容或排斥,從這點看出,Latch 的訪問,包括查詢也是互斥的,任何時候,只能有一個程式能pin住記憶體的某一塊,幸好這個過程是相當的短暫,否則系統效能將沒的保障

Latch只作用於記憶體中,他只能被當前例項訪問,而Lock作用於資料庫物件,在RAC體系中例項間允許Lock檢測與訪問

Latch是瞬間的佔用,釋放,Lock的釋放需要等到事務正確的結束,他佔用的時間長短由事務大小決定

Latch是非入隊的,而Lock是入隊的

Latch不存在死鎖,而Lock中存在。

Latch的cleanup

latch的使用過程中,可能會出現一些異常,而導致有些latch被異常佔有得不到釋放,這樣就會有問題了,別的程式過來請求不到。出現這樣的異常pmon程式會跟進處理,對於其處理的流程來說,最重要的莫過於將沒有提交的事物回滾,那麼就需要latch支援恢復,那麼latch在開始操作前會先寫一些資訊去latch的恢復區。Pmon 3秒鐘會自動執行一下,但是這也是很長的一段時間了,所以在程式在請求一個latch失敗多次之後,會post pmon程式去check一下佔有這個latchprocess是不是正常。

Latchlevel

Latch的級別分為0~14,15個級別,0級最低,14最高。如果兩個latch之間有聯絡,只能請求level更高的latch。原因如下:

如果a程式佔有一個level 5latch,它去請求一個level3latch,而程式b,佔有這個level3latch,又去請求那個level 5latch,這樣會有什麼問題呢?因為它是可以去spin的,又是可以去sleep的,sleep之後還是繼續重複,那就永遠沒有完沒有了了。所以呢,levelrequest是有level順序的,不能隨便的請求,只能由低階的latch去請求高階的latch

如果經常a一定要申請程式blatch的話,只能放棄原有latch level5為的latch重新對b程式的latch進行申請。

Latch資源爭用

如果latch資源被爭用,通常都會表現為CPU資源使用過高。

而反過來說,如果我們發現CPU資源很緊張,利用率總是在90%以上,甚至總是在100%,其主要原因有以下幾點。

1、SQL語句 如果沒有使用繫結變數,很容易造成頻繁讀寫shared pool裡的記憶體塊,如果存在大量的SQL被反覆分析,就會造成很大的Latch爭用和長時間的等待, 從而導致與解析SQL相關的共享池中的Latch爭用 。與 shared pool共享池相關的latchLibrary Cache Latch Shared Pool Latch。如果資料庫出現了上述latch的爭用,則有必要檢查下是否有正確使用繫結變數

2、 訪問頻率非常高的資料塊被稱為熱快(Hot Block),當很多使用者一起去訪問某幾個資料塊時,就會導致 資料緩衝池Latch 爭用,最常見的latch爭用有 :buffer busy waitscache buffer chain

Cache buffer chian:

當一個會話需要去訪問一個記憶體塊時,它首先要去一個像連結串列一樣的結構中去搜尋這個資料塊是否在記憶體中,當會話訪問這個連結串列的時候需要獲得一個Latch,如果獲取失敗,將會產生Latch cache buffer chain 等待,導致這個等待的原因是訪問相同的資料塊的會話太多或者這個列表太長(如果讀到記憶體中的資料太多,需要管理資料塊的hash列表就會很長,這樣會話掃描列表的時間就會增加,持有chache buffer chain latch的時間就會變長,其他會話獲得這個Latch的機會就會降低,等待就會增加)。

Buffer busy waits:

當一個會話需要訪問一個資料塊,而這個資料塊正在被另一個使用者從磁碟讀取到記憶體中或者這個資料塊正在被另一個會話修改時,當前的會話就需要等待,就會產生一個buffer busy waits等待。

產生這些Latch爭用的直接原因是太多的會話去訪問相同的資料塊導致熱快問題,造成熱快的原因可能是資料庫設定導致或者重複執行的SQL 頻繁訪問一些相同的資料塊導致。熱塊產生的原因不盡相同,按照資料塊的型別,可以分成以下幾種熱塊型別,不同熱塊型別處理的方式都是不同的:表資料塊、索引資料塊、索引根資料塊和檔案頭資料塊。

3、另外也有一些latch等待與bug有關,應當關注Metalink相關bug的公佈及補丁的釋出。為何latch的爭用會引起CPU使用率較高呢?

其實很容易理解,比如程式A持有latch,此時程式B也需要持有相關latch,但是沒有獲得,這時候程式B就需要進行spin,如果類似程式B的程式較多的話,對CPU進行spin的程式就會較多,表現也就是CPU利用率非常高,但是吞吐量卻很低,典型的“出工不出活”

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

相關文章