在今天的文章里我想談下SQL Server使用的更高級的,輕量級的同步對象:閂鎖(Latch)。閂鎖是SQL Server存儲引擎使用輕量級同步對象,用來保護多線程訪問內(nèi)存內(nèi)結(jié)構(gòu)。文章的第1部分我會介紹SQL Server里為什么需要閂鎖,在第2部分我會給你介紹各個閂鎖類型,還有你如何能對它們進行故障排除。
為什么我們需要閂鎖?
閂鎖首次在SQL Server 7.0里引入,同時微軟首次引入了行級別鎖(row-level locking)。對于行級別鎖引入閂鎖的概念是非常重要的,不然的話在內(nèi)存中會出現(xiàn)丟失更新(Lost Updates)的現(xiàn)象。如我所說的,閂鎖是存儲引擎使用的輕量級同步對象,是SQL Server用來保護內(nèi)存結(jié)構(gòu)的。閂鎖只不過是類似于多線程編程里的所謂的臨界區(qū)(Critcal Section)概念。
在傳統(tǒng)并發(fā)編程里,臨界區(qū)是同時只能一個線程運行的代碼。閂鎖本身是個臨界區(qū)的特殊版本,因為它允許多個并發(fā)讀操作。在SQL Server的上下文里這意味著多個線程可以并發(fā)讀取一個共享數(shù)據(jù)結(jié)構(gòu),例如內(nèi)存中的頁,但是寫入共享數(shù)據(jù)結(jié)構(gòu)必須是單個線程進行。
閂鎖是用來協(xié)調(diào)數(shù)據(jù)庫里多個線程物理執(zhí)行,然而鎖是基于選擇的事務(wù)隔離級別,用來邏輯獲得需要的隔離級別。作為開發(fā)者或DBA的你,你可以用不同方式影響鎖——例如通過SQL Server里的隔離級別,或者通過各種可用鎖提示。另一方面閂鎖是不能以直接方式控制的。在SQL Server里沒有閂鎖提示,也沒有可用閂鎖隔離級別。下表是鎖和閂鎖之間的比較:
鎖(Locks) 閂鎖(Latches)
控制…… 事務(wù) 線程
保護…… 數(shù)據(jù)庫內(nèi)容 內(nèi)存中數(shù)據(jù)結(jié)構(gòu)
模式…… 共享的(Shared), 保持(Keep),
更新(Update), 共享的(Shared),
排它的(Exclusive), 更新(Update),排它的(Exclusive),
意向的(Intension) 銷毀(Destroy)
死鎖…… 檢測并解決(detectionresolution) 通過嚴(yán)謹(jǐn)代碼來避免
保持在…… 鎖管理器的哈希表(Hashtable) 保護的數(shù)據(jù)結(jié)構(gòu)(Protected Data Structure)
從表里可以看到,閂鎖支持更細粒度保持(Keep)和銷毀(Destroy)模式。保持閂鎖主要用來引用計數(shù),例如當(dāng)你想知道在指定閂鎖上有多少其它閂鎖在等待。銷毀閂鎖是最有限制的一個(它甚至?xí)枞3珠V鎖),當(dāng)閂鎖被銷毀時會用到,例如當(dāng)惰性寫入器(Lazy Writer)想要釋放內(nèi)存中的頁時。我們先介紹下各種閂鎖模式,然后說下各個閂鎖模式的兼容性。
NL(空閂鎖):
內(nèi)部
未使用
KP(保持閂鎖):
可以由多個任務(wù)同時持有
只被一個DT模式的閂鎖阻塞
SH(共享閂鎖):
讀取數(shù)據(jù)頁的時候使用
可以由多個任務(wù)同事持有
阻塞EX模式和DT模式的閂鎖
UP(更新閂鎖):
寫入系統(tǒng)分配頁面和tempdb的行版本化頁面時使用
一個這種模式的閂鎖只能被一個單獨的任務(wù)持有
EX(排它閂鎖):
寫入數(shù)據(jù)頁的時候使用
一個這種模式的閂鎖只能被一個單獨的任務(wù)持有
DT(銷毀閂鎖):
很少使用
一個這種模式的閂鎖只能被一個單獨的任務(wù)持有

在SQL Server里,一致性不能只用鎖來獲得。SQL Server還是可以訪問沒被鎖管理器保護的共享數(shù)據(jù)結(jié)構(gòu),例如頁頭。還有SQL Server基于閂鎖基礎(chǔ)的其他組件也是,有單線程代碼路徑。好了,我們繼續(xù)講解SQL Server里的各種閂鎖類型,還有如何對它們進行故障排除。
閂鎖類型與故障排除
SQL Server區(qū)分3個不同閂鎖類別
IO閂鎖
緩沖區(qū)閂鎖(BUF)
非緩沖區(qū)閂鎖(Non-BUF)
我們來詳細看下這3個不同類別。當(dāng)在緩沖池的頁讀寫操作未完成——即當(dāng)你讀自/寫入你的存儲子系統(tǒng)時(2者未同步),SQL Server會使用IO閂鎖(I/O Latches)。對于這些I/O閂鎖,SQL Server在統(tǒng)計信息里以PAGEIOLATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。
復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGEIOLATCH_%'

使用這些閂鎖,SQL Server保證那些頁不會并發(fā)多次讀入緩存池,那些頁也不會從緩存池忽略,在那些頁需要被查詢訪問的時候。
除這些I/O閂鎖外,SQL Server也支持所謂的緩存區(qū)閂鎖(Buffer Latches),它用來保護緩沖池里頁不會被并發(fā)運行的線程影響。這些閂鎖,SQL Server使用它們來阻止內(nèi)存中的丟失更新(Lost Updates)。沒有這類閂鎖,在緩存池里會有并發(fā)的讀寫頁,它們會引發(fā)主內(nèi)存里頁的損壞。對于這些緩存閂鎖,SQL Server在統(tǒng)計信息里以PAGELATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。這里最重要的是你涉及了主內(nèi)存的競爭,因為他們的等待類型名稱里不包含IO字樣。
復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGELATCH_%'

最后SQL Server內(nèi)部使用所謂的非緩存區(qū)閂鎖(Non-Buffer Latches)來保護除緩沖池外的共享數(shù)據(jù)結(jié)構(gòu)。對于這些非緩存閂鎖,SQL Server在統(tǒng)計信息里以LATCH_為前綴出現(xiàn)。你可以在DMV sys.dm_os_wait_stats 查看下這些閂鎖類型的等待。
復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'LATCH_%'

但在這個DMV里這些對于非緩存區(qū)閂鎖的等待只是SQL Server內(nèi)部使用的各個閂鎖的概況信息,你可以在單獨的DMV sys.dm_os_latch_stats找到更詳細的信息。
復(fù)制代碼 代碼如下:
SELECT * FROM sys.dm_os_latch_stats

SQL Server 2014內(nèi)部使用163個閂鎖來同步共享數(shù)據(jù)結(jié)構(gòu)的訪問。其中一個著名的閂鎖是FGCB_ADD_REMOVE,它用來保護文件組的文件組控制阻塞( File Group Control Block (FGCB)),在以下特定操作期間:
文件增長(手動或自動)
增加/刪除文件組文件
重新計算填充比重(Recalculating proportional fill weightings)
在循環(huán)分配期間,通過文件組的文件回收。
當(dāng)你看到這個閂鎖排在前列是,你肯定有太多自動增長操作的問題,原因是你數(shù)據(jù)庫糟糕的默認配置。當(dāng)查詢嘗試讀/寫保護的數(shù)據(jù)結(jié)構(gòu)且需要等待一個閂鎖時,查詢就會進入掛起狀態(tài),直到閂鎖可以成功獲取。因此查詢經(jīng)過的整個查詢生命周期包括運行(RUNNING),掛起(SUSPENDED),可運行(RUNNABLE),最后再次運行(RUNNING)。因此,當(dāng)查詢長時間把持閂鎖時,強制共享數(shù)據(jù)結(jié)構(gòu)保護才有意義。那是因為改變查詢狀態(tài)也意味著進行Windows系統(tǒng)里的上下文切換,依據(jù)引入的CPU周期是個很昂貴的操作。
因此對于讀寫頻繁或極短時間內(nèi)的共享數(shù)據(jù)結(jié)構(gòu)上放上閂鎖沒有意義。在這個情況下,需要的上下文切換會殺死SQL Server的整體性能,它需要花費太多的時間來完成整個查詢生命周期(運行(RUNNING),掛起(SUSPENDED),可運行(RUNNABLE))。那就是是SQL Server引入的所謂自旋鎖(Spinlocks)。鎖管理器就是這樣數(shù)據(jù)結(jié)構(gòu)的好例子:當(dāng)鎖定或解鎖數(shù)據(jù)對象(例如記錄,頁等)時只需要單個線程訪問。但當(dāng)你查看sys.dm_os_latch_stats時,你會發(fā)現(xiàn)沒有閂鎖保護鎖管理器本身。鎖管理器使用的哈希表里對應(yīng)的哈希桶使用自旋鎖來保護——LOCK_HASH自旋鎖。通過鎖管理器執(zhí)行鎖定和解鎖操作前,必須獲得自旋鎖。
以上就是本文的全部內(nèi)容,希望大家可以喜歡。
您可能感興趣的文章:- 淺析Sql server鎖,獨占鎖,共享鎖,更新鎖,樂觀鎖,悲觀鎖