標籤:深入理解oracle中的latch
深入理解Oracle中的latch
序列化 概述
序列化 - 資料庫系統本身是一個多使用者並發處理系統,在同一個時間點上,可能會有多個使用者同時操作資料庫, 多個使用者同時在相同的物理位置上寫資料時,不能發生互相覆蓋的情況,這叫做序列化,序列化會降低系統的並發性,但這對於保護資料結構不被破壞來說則是必需的。在Oracle資料庫中,通過閂鎖(latch)和鎖定(lock)來解決這兩個問題。
閂鎖和鎖定既有相同點又有不同點。相同點在於它們都是用於實現序列化的資源。而不同點則在於閂鎖(Latch)是一個低層級、輕量級的鎖,獲得和釋放的速度很快,以類似於號誌的方式實現。而鎖定(Lock)則可能持續的時間很長,通過使用隊列,按照先進先出的方式實現。也可以簡單地理解為閂鎖是微觀領域的,而鎖定則是宏觀領域的。
注意 :latch是用於保護SGA區中共用資料結構的一種序列化鎖定機制。它不僅僅用於buffer cache, 還用於shared pool以及log buffer等。
閂鎖(latch)概述
Oracle資料庫使用閂鎖(latch)來管理SGA記憶體的分配和釋放.Latch是用於保護SGA區中共用資料結構的一種序列化鎖定機制。Latch的實現是與作業系統相關的,尤其和一個進程是否需要等待一個latch、需要等待多長時間有關。
Latch是一種能夠極快地被擷取和釋放的鎖,它通常用於保護描述buffer cache中block的資料結構。與每個latch相聯絡的還有一個清除過程,當持有latch的進程成為死進程時,該清除過程就會被調用。Latch還具有相關層級,用於防止死結,一旦一個進程在某個層級上得到一個latch,它就不可能再獲得等同或低於該層級的latch。
Latch 不會造成阻塞,只會導致等待。 阻塞是一種系統設計上的問題,等待是一種系統資源爭用的問題。
SPIN與休眠
SPIN
在performance tuning的sg上tuning 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次數而遞增,以厘秒為單位,如1,1,2,2,4,4,8,8,。。。休眠的閥值限制由隱含參數_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 latch和library cache latch是採用這個機制。
如果將隱含參數_latch_wait_posting設定為2,則所有Latch都採用這種等待方式,使用這種方式能夠比較精確的喚醒某個等待的進程,但維護Latch Wait List需要系統資源,並且對Latch Wait List上Latch的競爭也可能出現瓶頸。
如果一個進程請求,旋轉,休眠Latch用了很長時間,他會通知PMON進程,查看Latch的佔用進程是否已經意外終止或死亡,如果是則PMON會清除釋放佔用的Latch資源。
總之, Latch擷取的流程:請求-SPIN-休眠-請求-SPIN-休眠 ... ... 佔用。
不等待(No-Wait)
這種類型的latch比較少,對於這種類型的latch來說,都會有很多個可用的latch。當一個進程請求其中的一個latch時,會以no-wait模式開始請求。如果所請求的latch不可用,則進程不會等待,而是立刻請求另外一個latch。只有當所有的latch都不能獲得時,才會進入等待。
latch的擷取過程可以用來概括
650) this.width=650;" width="488" src="http://img14.poco.cn/mypoco/myphoto/20130109/19/5616035720130109190148054.png" height="473" style="border:0px;" />
Latch和Lock的區別
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一下佔有這個latch的process是不是正常。
Latch的level
Latch的層級分為0~14,共15個層級,0級最低,14最高。如果兩個latch之間有聯絡,只能請求level更高的latch。原因如下:
如果a進程佔有一個level 為5的latch,它去請求一個level為3的latch,而進程b,佔有這個level為3的latch,又去請求那個level 為5的latch,這樣會有什麼問題呢?因為它是可以去spin的,又是可以去sleep的,sleep之後還是繼續重複,那就永遠沒有完沒有了了。所以呢,level的request是有level順序的,不能隨便的請求,只能由低級的latch去請求進階的latch。
如果經常a一定要申請進程b的latch的話,只能放棄原有latch level5為的latch重新對b進程的latch進行申請。
Latch資源爭用
如果latch資源被爭用,通常都會表現為CPU資源使用過高。
而反過來說,如果我們發現CPU資源很緊張,利用率總是在90%以上,甚至總是在100%,其主要原因有以下幾點。
1、SQL語句 如果沒有使用綁定變數,很容易造成頻繁讀寫shared pool裡的記憶體塊,如果存在大量的SQL被反覆分析,就會造成很大的Latch爭用和長時間的等待, 從而導致與解析SQL相關的共用池中的Latch爭用 。與 shared pool共用池相關的latch有Library Cache Latch 和Shared Pool Latch。如果資料庫出現了上述latch的爭用,則有必要檢查下是否有正確使用綁定變數
2、 訪問頻率非常高的資料區塊被稱為熱快(Hot Block),當很多使用者一起去訪問某幾個資料區塊時,就會導致 資料緩衝池Latch 爭用,最常見的latch爭用有 :buffer busy waits和cache 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利用率非常高,但是輸送量卻很低,典型的“出工不出活”
本文出自 “linux相關技術” 部落格,謝絕轉載!
深入理解Oracle中的latch