Oracle Latch及latch衝突

tolywang發表於2007-08-17

Latch及latch衝突

引言
Oracle Rdbms應用了各種不同型別的鎖定機制,latch即是其中的一種,本文將集中介紹latch(閂)的概念,理解latch的實現方法並說明引起latch衝突的原因。

什麼是latch


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

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

Latch與Enqueue(佇列)

Enqueue是Oracle使用的另一種鎖定機制,它更加複雜,允許幾個併發程式不同程度地共享某些資源。任何可被併發使用的物件均可使用enqueue加以保護。一個典型的例子是表的鎖定,我們允許在一個表上有不同級別的共享。與latch不同之處在於,enqueue是使用作業系統特定的鎖定機制,一個enqueue允許使用者在鎖上存貯一個標記,來表明請求鎖的模式。作業系統lock manager跟蹤所有被鎖定的資源,如果某個程式不能獲取它所請求的那種鎖,作業系統就把請求程式置於一個等待佇列中,該佇列按FIFO原則排程,而在latches中是沒有象enqueue中排序的等待佇列,latch等待程式要麼使用定時器來喚醒和重試,要麼spin(只用於多處理器情況下)。

何時需要latch

當一個程式準備訪問SGA中的資料結構時,它就需要獲得一個latch。當程式獲得latch後,它將一直持有該latch直到它不再使用此資料結構,這時latch才會被釋放。可透過latch名稱來區分它所保護的不同資料結構。

Oracle使用元指令對latch進行操作, 當所需的latch已被其他程式持有時,執行指令程式將停止執行部分指令,直到該latch被釋放為止。從根本上講,latch防止併發訪問共享資料結構,由於設定和釋放latch的指令是不可分割的,作業系統就可以保證只有一個程式獲得latch,又由於這只是單條指令,所以執行速度很快。latch被持有的時間是很短,而且提供了當持有者不正常中斷時的清除機制,該清除工作是由Oracle後臺程式PMON來完成的。

什麼導致latch衝突

Latch保護SGA中的資料結構被多個使用者同時訪問,如果一個程式不能立即得到所需latch,它就必須等待,這就導致了CPU的額外負擔和系統的速度降低。額外的CPU使用是程式‘spining’導致的,‘spining’是指程式定時地重複嘗試獲取latch,在連續兩次之間,程式處於休眠狀態,在得到latch之前,spining過程將重複進行下去。

如何標識內部latch的衝突

Server manager monitor是一個相當有用的來監視latch等待、請求和衝突的工具。也可查詢相關的資料字典表:v$latch, v$latchholder, v$latchname。

v$latch表的每一行包括了對不同型別latch的統計,每一列反映了不同型別的latch請求的活動情況。不同型別的latch請求之間的區別在於,當latch不可立即獲得時,請求程式是否繼續進行。按此分類,latch請求的型別可分為兩類:willing-to-wait和immediate。

Willing-to-wait : 是指如果所請求的latch不能立即得到,請求程式將等待一很短的時間後再次發出請求。程式一直重複此過程直到得到latch。

Immediate:是指如果所請求的latch不能立即得到,請求程式就不再等待,而是繼續執行下去。

在v$latch中的以下欄位反映了Willing-to-wait請求:

GETS---成功地以Willing-to-wait請求型別請求一個latch的次數。

MISSES---初始以Willing-to-wait請求型別請求一個latch不成功的次數。

SLEEPS---初始以Willing-to-wait請求型別請求一個latch不成功後,程式等待獲取latch的次數。

在v$latch中的以下欄位反映了Immediate類請求:

IMMEDIATE_GETS---以Immediate請求型別成功地獲得一個latch的次數。

IMMEDIATE_MISSES---以Immediate請求型別請求一個latch不成功的次數。

我們可以透過對v$latch, v$latchholder, v$latchname的查詢獲得有關latch資訊,例如:

/* 已知一個latch地址,找到latch名字 */

col name for a40

select a.name from v$latchname a, v$latch b

where b.addr = '&addr'

and b.latch#=a.latch#;

/* 顯示系統範圍內的latch統計 */

column name format A32 truncate heading "LATCH NAME"

column pid heading "HOLDER PID"

select c.name,a.addr,a.gets,a.misses,a.sleeps,

a.immediate_gets,a.immediate_misses,b.pid

from v$latch a, v$latchholder b, v$latchname c

where a.addr = b.laddr(+)

and a.latch# = c.latch#

order by a.latch#;

/* 由latch名稱顯示對latch的統計 */

select c.name,a.addr,a.gets,a.misses,a.sleeps,

a.immediate_gets,a.immediate_misses,b.pid

from v$latch a, v$latchholder b, v$latchname c

where a.addr = b.laddr(+) and a.latch# = c.latch#

and c.name like '&latch_name%' order by a.latch#;

latch有40餘種,但作為DBA關心的主要應有以下幾種:

Cache buffers chains latch: 當使用者程式搜尋SGA尋找database cache buffers時需要使用此latch。

Cache buffers LRU chain latch: 當使用者程式要搜尋buffer cache中包括所有 dirty blocks的LRU (least recently used) 鏈時使用該種latch。

Redo log buffer latch: 這種latch控制redo log buffer中每條redo entries的空間分配。

Row cache objects latch: 當使用者程式訪問快取的資料字典數值時,將使用Row cache objects latch。

下面我們將著重介紹一下如何檢測和減少redo log buffer latch的衝突。對redo log buffer的訪問是由redo log buffer latch來控制的,這種latch有兩種型別, redo allocation latch和redo copy latch。

Redo allocation latch控制redo entries在redo log buffer中的空間分配。Oracle的一個使用者程式只有得到redo allocation latch後才能為redo entries在redo log buffer中分配空間,又由於一個instance只有一個redo allocation latch,所以一次只有一個使用者程式在buffer中分配空間。當使用者程式獲得latch後,首先為redo entry分配空間,然後程式繼續持有latch並複製entry到buffer中,這種複製稱為“在redo allocation latch上的複製”(copying on the redo allocation latch),複製完畢後,使用者程式釋放該latch。

一個“在redo allocation latch上的複製”的redo entry的最大值是由初始化引數LOG_SMALL_ENTRY_MAX_SIZE定義的,根據作業系統的不同而不同。

Redo Copy Latch只應用於多CPU的系統。在多CPU的instance中,如果一個redo entry太大,超過了LOG_SMALL_ENTRY_MAX_SIZE定義值,則不能進行“在redo allocation latch上的複製”, 此時使用者程式必須獲取redo copy latch。一個instance中可以有多個redo copy latch,其數目由初始引數LOG_SIMULTANEOUS_COPIES決定,預設值為CPU數目。

在單CPU情況下,不存在redo copy latch,所有的redo entry無論大小, 都進行“在redo allocation latch上的複製”。

對redo log buffer的過多訪問將導致redo log buffer latch的衝突,latch衝突將降低系統效能,我們可透過如下查詢來檢測這種latch衝突:

col name for a40

SELECT ln.name,gets,misses,immediate_gets,immediate_misses

FROM v$latch l,v$latchname ln

WHERE ln.name IN('redo allocation','redo copy') AND ln.latch#=l.latch#

/

若misses與gets的比例超過1%或immediate_misses與(immediate_gets+immediate_misses)比例超過1%時,應考慮採取措施減少latch的衝突。

大多數的redo log buffer latch衝突是在多個CPU情況下,兩個或多個Oracle程式試圖同時得到相同的latch發生的。由於一個instance只有一個redo allocation latch,為減少redo allocation latch的衝突,應減少單個程式持有latch的時間,這可以透過減小初始引數LOG_SMALL_ENTRY_MAX_SIZE以減小redo entry的數目和大小來實現。如果觀察到有redo copy latch衝突,可以透過增大LOG_SIMULTANEOUS_COPIES 初始引數來加大latch數目,其預設值為CPU數目,最大可增大到CPU數目的兩倍。

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

相關文章