理解數(shù)據(jù)庫(kù)原理可能是找到破解疑難雜癥最后一張拼圖的關(guān)鍵
以前和一些年輕的DBA溝通的時(shí)候,他們總是對(duì)我們這種二十年前的DBA總?cè)ヌ骄磕承?shù)據(jù)庫(kù)內(nèi)部實(shí)現(xiàn)機(jī)理感到不能理解。他們覺得現(xiàn)在要學(xué)的東西太多,學(xué)習(xí)各種操作和實(shí)施方案就夠費(fèi)勁了,還花那么多精力去細(xì)摳一些很可能八百年都用不上的屠龍技,意義并不大。確實(shí),我們這些年在Oracle的一些內(nèi)部原理方面的知識(shí)都是一些碎片化的屠龍技,不是遇到問(wèn)題的時(shí)候,真的沒(méi)有太多其他的用處。不過(guò)在一些復(fù)雜問(wèn)題定位的時(shí)候,這些知識(shí)往往是找到解決問(wèn)題辦法的關(guān)鍵。
前陣子有個(gè)券商的系統(tǒng)出現(xiàn)了一次故障,交易在3秒鐘左右的時(shí)間里出現(xiàn)了嚴(yán)重卡頓,影響到了幾百筆關(guān)鍵業(yè)務(wù)的成交。為了避免類似問(wèn)題再出現(xiàn),領(lǐng)導(dǎo)希望找到根因。
圖片
從AWR報(bào)告的TOP EVENTS上看到了幾個(gè)疑點(diǎn),分別是Log File SYNC、enq TX-INDEX CONTENTION和Control File Sequential Read。這三種等待確實(shí)都可能引發(fā)幾秒鐘的卡頓。當(dāng)時(shí)駐場(chǎng)服務(wù)的維保廠商認(rèn)定是log fie sync引發(fā)了卡頓,要去考慮如何優(yōu)化REDO方面的問(wèn)題。我看了這個(gè)等待后,第一反應(yīng)是索引引發(fā)的行鎖等待的可能性更大一些,因?yàn)槠骄訒r(shí)夠大。
3秒鐘的抖動(dòng),在30分鐘的報(bào)告里可能會(huì)被稀釋。以前我也寫文章談過(guò)這個(gè)問(wèn)題,宏觀分析用AWR,而微觀分析要用ASH。有經(jīng)驗(yàn)的DBA一般會(huì)在這個(gè)時(shí)候?qū)С鯝SH數(shù)據(jù),然后在EXCEL里去做分析。在我們的DBAIOPS運(yùn)維知識(shí)自動(dòng)化系統(tǒng)中,就是通過(guò)ASH數(shù)據(jù)去做根因定位的。
圖片
拿到ASH數(shù)據(jù),第一步是刪除與本次分析無(wú)關(guān)的列,然后另存一個(gè)文件。Oracle的ASH數(shù)據(jù)的列太多了,看起來(lái)很浪費(fèi)時(shí)間。這是為了分析本次問(wèn)題我留下的列。其實(shí)不同的問(wèn)題分析留下的列會(huì)略有不同,但是大同小異。
圖片
第二步就是對(duì)EVENT進(jìn)行篩選,找出所有你需要分析的等待事件的樣本。找出enq: TX - index contention等待事件的所有行,然后去發(fā)現(xiàn)規(guī)律。我們過(guò)濾出了400多行,數(shù)量不多,這對(duì)于定位問(wèn)題是十分好的兆頭。
圖片
下一步把這些行拷貝到另外一個(gè)EXECL頁(yè)里,進(jìn)行進(jìn)一步分析。接下來(lái)我們通過(guò)Blocking_session去找阻塞者,太幸運(yùn)了。只找到一條記錄。會(huì)話4756。
圖片
這時(shí)候我們要回到原始文件中繼續(xù)分析,注意:一定要回到原始文件,因?yàn)?span>enq: TX - index contention還有個(gè)相類似的等待事件enq: TX - row lock contention,其最終影響是類似的。大多數(shù)阻塞都存在類似的問(wèn)題。過(guò)濾阻塞會(huì)話為4756的會(huì)話,發(fā)現(xiàn)有426條。與當(dāng)時(shí)400多筆交易受影響的現(xiàn)象十分吻合。
圖片
下面就需要繼續(xù)分析會(huì)話4756了。找出4756存在的問(wèn)題,就找到了解決問(wèn)題的鑰匙。于是在原始表格中搜索4756會(huì)話。這個(gè)會(huì)話只有3條記錄,是三個(gè)連續(xù)采樣周期的數(shù)據(jù),相隔一秒,3秒鐘也正好與系統(tǒng)故障阻塞的3秒鐘左右相吻合。看來(lái)這回是真正找到真兇了。
圖片
在這里我們發(fā)現(xiàn)了一個(gè)十分奇怪的現(xiàn)象,這個(gè)會(huì)話實(shí)際上也在執(zhí)行一條INSERT語(yǔ)句,而且是與被阻塞的會(huì)話的SQLID是完全相同的。從三個(gè)采樣上看,這條SQL是一次執(zhí)行持續(xù)了3秒鐘,因?yàn)槲覀兛吹絊QL_EXEC_ID是同一個(gè)。一條簡(jiǎn)單的單行INSERT語(yǔ)句持續(xù)執(zhí)行了3秒鐘,這太不合理了??吹降却录?,都是db file sequential read,USER/IO類的等待。
至此,問(wèn)題分析的前半段就基本上明確了,問(wèn)題基本上定位。但是為了防止類似問(wèn)題再發(fā)生,必須找出根因。維保廠商給出的日志同步的結(jié)論基本上可以推翻了,雖然說(shuō)LOG FILE SYNC也能解釋某些INSERT緩慢的問(wèn)題,但是4756壓根沒(méi)有等待過(guò)LOG FILE SYNC,所以不可能是日志同步引發(fā)的本次故障。
定位清楚根因?qū)τ趶氐赘祟悊?wèn)題十分關(guān)鍵,因此本次分析尚未完成,還需要繼續(xù)分析下去??赡苌厦娴姆治鯝SH數(shù)據(jù)的過(guò)程大家還常用一些,下面就要介紹一些不常用的技巧了。
圖片
在Oracle導(dǎo)出的ASH數(shù)據(jù)的尾部,有很多十分有價(jià)值的 DELTA數(shù)據(jù),就是兩次采樣之間,這個(gè)SESSION的一些開銷。從這些開銷可以推理出很多細(xì)微的問(wèn)題來(lái),對(duì)于定位問(wèn)題十分關(guān)鍵。
從上面的數(shù)據(jù)里可以分析出,這個(gè)會(huì)話在執(zhí)行這條INSERT的時(shí)候,產(chǎn)生了大量的物理IO,加在一起接近46M。案例說(shuō)INSERT不應(yīng)該產(chǎn)生如此多的物理IO的。這張表很熱,INSERT所需要的大部分?jǐn)?shù)據(jù)塊(包含索引和表)都應(yīng)該是在DB CACHE里的。其實(shí)在看到enq: TX - index contention這個(gè)等待事件的時(shí)候,我第一反應(yīng)就是索引分裂。當(dāng)時(shí)和用戶DBA討論這個(gè)問(wèn)題的時(shí)候,也和他們一起分析了AWR報(bào)告里的葉節(jié)點(diǎn)分裂和枝節(jié)點(diǎn)分裂的統(tǒng)計(jì)數(shù)據(jù),葉節(jié)點(diǎn)分裂大概每秒10個(gè),枝節(jié)點(diǎn)分裂為0.2。葉節(jié)點(diǎn)分裂對(duì)于如此高并發(fā)的系統(tǒng)來(lái)說(shuō)算是比較多的,但是還可以接受。不過(guò)枝節(jié)點(diǎn)分裂就有點(diǎn)過(guò)高了。
其實(shí)到這個(gè)地方,傳統(tǒng)的分析過(guò)程已經(jīng)完畢。下面就要依靠分析問(wèn)題的人的知識(shí)是否足以支撐下面的推理了。因?yàn)楹竺嬷荒芸客评?,而缺少?shí)際數(shù)據(jù)支撐了。要分析的問(wèn)題是為什么一條簡(jiǎn)單的單行INSERT會(huì)產(chǎn)生接近50M的物理讀。在我的知識(shí)體系里,索引維護(hù)可能是最有可能的答案了。如果索引的節(jié)點(diǎn)分裂的時(shí)候,需要寫入新數(shù)據(jù)的前臺(tái)進(jìn)程需要負(fù)責(zé)維護(hù)這個(gè)分裂過(guò)程,如果索引中存在大量的碎片,那么在這樣一次操作中可能會(huì)掃描大量的索引塊,引發(fā)此類問(wèn)題。這種情況往往在于使用很長(zhǎng)時(shí)間沒(méi)有維護(hù)過(guò)索引的系統(tǒng)中發(fā)生。但是本系統(tǒng)是一個(gè)券商的交易系統(tǒng),這張表每個(gè)交易日結(jié)束都會(huì)TRUNCATE 的,因此這種情況不會(huì)發(fā)生。
那么下一種可能就是索引的“大分裂”,甚至可能是BLEVEL的重建,如果表足夠大,而且數(shù)據(jù)足夠冷,寫入后不怎么訪問(wèn)。那么很可能重建BLEVEL的時(shí)候,很可能需要掃描很多不在內(nèi)存中的索引塊,從而引發(fā)這個(gè)問(wèn)題。這張表正好又是交易日志表,在交易時(shí)間內(nèi),基本上寫入后不會(huì)訪問(wèn)的,很符合這個(gè)條件。我覺得這個(gè)解釋目前是最為合理的。因此如果要避免此類問(wèn)題發(fā)生,把這張表做成HASH表可能是最佳的解決方案。
其實(shí)定位這個(gè)故障的最關(guān)鍵的一個(gè)拼圖就是對(duì)Oracle數(shù)據(jù)庫(kù)的前臺(tái)進(jìn)程維護(hù)索引的原理的理解,如果你不掌握這個(gè)知識(shí),那么分析到最后的推理往往會(huì)發(fā)生偏差,從而影響根因定位。實(shí)際上在b-tree結(jié)構(gòu)的數(shù)據(jù)庫(kù),比如MYSQL上,此類問(wèn)題發(fā)生得更加頻繁。以前我就幫助用戶分析過(guò)幾次MYSQL的簡(jiǎn)單INSERT 偶發(fā)性緩慢的問(wèn)題,其原因和這個(gè)問(wèn)題是十分類似的。
這些理論雖然可用的場(chǎng)景有限,不過(guò)如果你想成為分析問(wèn)題的高手,還是需要去多學(xué)學(xué)數(shù)據(jù)庫(kù)的一些基礎(chǔ)理論,甚至理解到算法層面。今天這篇文章寫得有點(diǎn)費(fèi)勁,寫到這里已經(jīng)快9點(diǎn)了,后面還有些話好像沒(méi)寫痛快,不過(guò)還有其他事情要做,今天就先到這里吧。