一、問題描述
此種現(xiàn)象實(shí)則少見,一旦遇見,如沒有處理經(jīng)驗(yàn)足以令一個(gè)身經(jīng)百戰(zhàn)sql server DBA懷疑人生,從業(yè)18年sql server數(shù)據(jù)庫以來,第二次遇見,和第一次遇到一樣瞬間被打入懵逼狀態(tài)
? ? 遇到的問題,進(jìn)程大量阻塞,大量的僵尸進(jìn)程,影響就是整個(gè)數(shù)據(jù)庫處于hang死狀態(tài),客戶端請(qǐng)求大量超時(shí),干脆就請(qǐng)求不進(jìn)來,數(shù)據(jù)庫服務(wù)器cpu并不高,在30%左右。
1)kill進(jìn)程,解決不了,正所謂kill我一個(gè),會(huì)有千千萬萬個(gè)我馬上沖進(jìn)來
2)重啟數(shù)據(jù)庫服務(wù)器,解決不了,重啟完了,進(jìn)程馬上阻塞
3)優(yōu)化sql,解決不了,大量被阻塞的都是主鍵key-value的update單條語句,insert單條語句,甚至是阻塞源
4)只能程序端一個(gè)模塊一個(gè)模塊的服務(wù)器停止,直到某個(gè)模塊停止服務(wù),阻塞解開
第一次遇見此問題是2年前,也就是2018年3,4月份,當(dāng)時(shí)數(shù)據(jù)庫處于hang死狀態(tài),hang死一段時(shí)間后,always on 的1主8從的某些從庫會(huì)跟主庫斷開同步。針對(duì)此種問題束手無策,DBA經(jīng)理決定跟微軟開了case,case部署一套監(jiān)控,監(jiān)控出來的數(shù)據(jù)都是16進(jìn)制,看著像編譯語言,文件反饋給微軟分析。微軟一個(gè)女工程師反饋,反饋的是針對(duì)一個(gè)自動(dòng)增長表內(nèi)存資源爭用問題,需要程序調(diào)整解決。數(shù)據(jù)庫在程序解決前要做的是做了一個(gè)監(jiān)控循環(huán)腳本,當(dāng)監(jiān)控進(jìn)程的一個(gè)參數(shù)到某一個(gè)臨界值,就kill進(jìn)程(只可惜后來賭氣離職走人,筆記本也被我撒氣摔壞了,此監(jiān)控腳本在我這里已石沉大海),kill進(jìn)程有點(diǎn)粗魯,甚至有點(diǎn)殘暴,但總比整個(gè)數(shù)據(jù)庫hang死要好很多。那段好幾天電話跟那個(gè)微軟女工程師溝通交流,聲音比較甜美,起碼四個(gè)+號(hào),本來就對(duì)微軟工程師有崇敬之感,又一女工程,崇敬感加倍!不過,轉(zhuǎn)面一想,能挑起微軟工程師職位,想必是李莫愁,滅絕師太級(jí)的人物吧,嘿嘿
二、問題源頭
此種問題不是通常慢查詢,加加索引,優(yōu)化一下sq就能搞定的。因?yàn)槁樵兪锹?,但他自己在玩,并不影響別人。這個(gè)問題的現(xiàn)象不是,一些簡單的key-value的單條主鍵update或者單條insert語句被阻塞,甚至成為阻塞源。此刻,一個(gè)叫做“閂鎖”的名詞該閃亮登場了。
閂鎖是SQL Server存儲(chǔ)引擎使用輕量級(jí)同步對(duì)象,用來保護(hù)多線程訪問內(nèi)存內(nèi)結(jié)構(gòu)。
對(duì)于行級(jí)別鎖引入閂鎖的概念是非常重要的,不然的話在內(nèi)存中會(huì)出現(xiàn)丟失更新(Lost Updates)的現(xiàn)象。如我所說的,閂鎖是存儲(chǔ)引擎使用的輕量級(jí)同步對(duì)象,是SQL Server用來保護(hù)內(nèi)存結(jié)構(gòu)的。閂鎖只不過是類似于多線程編程里的所謂的臨界區(qū)(Critcal Section)概念。
在傳統(tǒng)并發(fā)編程里,臨界區(qū)是同時(shí)只能一個(gè)線程運(yùn)行的代碼。閂鎖本身是個(gè)臨界區(qū)的特殊版本,因?yàn)樗试S多個(gè)并發(fā)讀操作。
閂鎖是用來協(xié)調(diào)數(shù)據(jù)庫里多個(gè)線程物理執(zhí)行,然而鎖是基于選擇的事務(wù)隔離級(jí)別,用來邏輯獲得需要的隔離級(jí)別。作為開發(fā)者或DBA的你,你可以用不同方式影響鎖——例如通過SQL Server里的隔離級(jí)別,或者通過各種可用鎖提示。
然而閂鎖是不能以直接方式控制的。在SQL Server里沒有閂鎖提示,也沒有可用閂鎖隔離級(jí)別。下表是鎖和閂鎖之間的比較:
鎖(Locks)閂鎖(Latches)

三、閂鎖處理
面對(duì)閂鎖,DBA束手無策,處理需要開發(fā)重改架構(gòu)代碼,大家都知道一個(gè)大數(shù)據(jù)量的系統(tǒng),有太多事務(wù)就已經(jīng)很dei兒,要是事務(wù)里面還有很多線程,或者引起閂鎖的自動(dòng)增長內(nèi)存資源搶占問題,更是dei兒上加dei兒!
數(shù)據(jù)庫hang死,如果進(jìn)程里wait_type會(huì)有大量的PAGELATCH出現(xiàn),這時(shí)候就考慮一下閂鎖問題,先一個(gè)模塊一個(gè)模塊的試,定位到相應(yīng)引起閂鎖的模塊,此模塊如有有自動(dòng)增長或者多線程,如果還有事務(wù)就大事務(wù)化小事務(wù),小事務(wù)化無,多線程不適合用oltp里面,盡量減少或者干脆就消除,多線程可以用在olap里面。對(duì)于自動(dòng)增長的這種,目前我還沒想到該如何處理,設(shè)計(jì)上盡量讓操作同一自增長表不同sql盡量不在小事務(wù)上相互交叉,別相互在內(nèi)存爭資源。
四、結(jié)束語
對(duì)技術(shù)無論何時(shí)何地都該懷有敬畏之心。不能裝逼,雖說裝逼裝的好容易當(dāng)領(lǐng)導(dǎo),但在技術(shù)領(lǐng)域上永遠(yuǎn)在路上。