作為一名混迹數據庫江湖十幾年的老 DBA,當你對關系型數據庫的了解越來越深入時,你會發現,ORACLE 數據庫真的是強大到令人發紫!
Oracle 數據庫的強大,不僅體現在其對 ACID 的巧妙實現,其對高并發的完美支持,更重要的是他的可管理性,包括可度量、可回溯,以及出現問題後的問題核查接口和問題檢查方法論,真是強大到令人發紫, 這是其他關系型數據庫短期内還無法超越的。
問題來了!!!!
電話響了,是某銀行一位熟悉的資深 DBA 的來電。
“在嗎?現在應用連接數據庫會 hang 住,sysdba 登陸也會 hang 住,無報錯,該如何處理?”
沒有往日的寒暄和客套,直入主題!
人的聲音是有表情的,從電話那頭急促的語氣,不難判斷,客戶很着急。
可能有些朋友不清楚數據庫登錄 hang 住是怎樣的一種現象,下圖可以腦補一下:
也就是說,正常的登錄是可以快速看到 “SQL>” 這樣的提示符的,但出現異常時,就會長時間等不到 “SQL>” 這樣的提示符, 這就是所謂的登錄數據庫會 hang 住。
看到這裡,有些朋友開始激動了,要猜一下原因,試一下身手!
1)是不是數據庫歸檔滿了?
答:這… 歸檔滿了,sysdba 登錄會報 ORA - 歸檔錯誤相關的提示!而且注意細節,之前提到了,客戶是資深的 DBA,顯然這種可能性早就被排除掉了, 注意細節啊 ^_^
2)查一下等待事件,看看在等什麼呢?
答:這… 數據庫都連不進去了,怎麼發出 SQL 來查詢呢…
3)alert 日志有什麼明顯報錯麼?
答:在這個 case 中 alert 日志沒有報錯,也沒有明顯問題…
三闆斧用完後,接下來不妨思考個兩三分鐘,如果是你,接下來你要怎麼指揮這場戰鬥…
“别着急,你收兩個 SSD 保存現場,然後殺掉 pmon,先恢複業務,然後把 SSD 的 trace 發我,我來做下 RCA!”
客戶殺完 pmon 進程,數據庫自動重啟後,業務恢複正常。随後将 SSD 發了過來。
這裡有些同學聽到這些術語,有些摸不着頭腦了:
什麼是 SSD?固态盤(不會吧)?
還有什麼是 RCA 呢?
這裡給大家科普一下:
SSD 其實就是 System State Dump, 系統即時狀态 DUMP 的首字母組合,
RCA 就是 Root Cause Analyze, 根因分析,是解決問題的難度要大許多,也有意思許多
為什麼要收集 SSD 呢?
因為原因的不确定性,怎麼能抓到蝴蝶效應中的那隻蝴蝶呢?那就需要足夠的信息!
多年前未掌握 SSD 這個功能的時候,出現問題,喜歡收集 v$session,v$session_wait,v$sqlarea,v$lock 等動态性能的相關信息,然後重啟,但是後來往下分析的時候,發現少收集了什麼信息,導緻分析不順利,後悔莫及…
當時就在想,Oracle 是否有一個一鍵收集的功能:
把想要的,不想要的,全都收集下來呢!答案就是 SSD。
甚至是當 sysdba 無法登陸時,Oracle 依然可以直接 attach 到共享内存,将内存中的即時狀态全部抓取下來,包括系統當前各個進程正在執行什麼、正在等什麼、進城的堆棧等信息,真是強大大令人發紫的一個功能。
SSD 的收集非常簡單,照敲就是了,以下是 SSD 收集的命令
### sqlplus -prelim "/as sysdba"
SQL>oradebug setmypid
SQL>oradebug dump systamstate 266
SQL>-- 等上 30 秒到 1 分鐘
SQL>oradebug dump systamstate 266
SQL>oradebug tracefile_name
接下來就帶領大家一起去分析 SSD,做根因分析,你會發現工作是一件多麼有趣的事情。
1. 查看登陸進程在等什麼
從 xxdb_ora_33030248.trc 中搜索 "waiting for" 可以看到:
可以看到:
1)有N 個進程都在等 LATCH:librarycache,latch, 并且 latch 是同一個即 70000006b9d8008
2) 1個進程在等 cursor:pin X,即在等待 cursor 類型的 mutex
3) latch 等待的時間已經長達達到 3723 秒
這裡不難看出:
由于登陸的時候,要執行包括驗證用戶、獲取權限等内部的 SQL(遞歸 SQL),但是在發出 SQL 後,由于長時間無法獲取 latch:library cache 這樣的資源,因此登陸看上去就像 hang 住了一樣… 接下來,我們隻需要找到無法 latch:library cache 的原因,就可以解開數據庫 hang 住的真相了!
2. 第一次頭腦風暴
看到這裡,也許有同學迫不及待地又想再試試身手:
是不是硬解析的問題?
可以看到:
當客戶端發出的 SQL 到達數據庫的服務進程後,要先在 shared pool 中去找内存中是否存在該 SQL 和執行計劃,如果存在則拿到執行計劃直接執行即可。
那麼 oracle 是如何查找的呢?就是對 SQL 文本計算 hash 值後,獲取 latch:library cache(11g 中則采用 mutex 代替),對對應的鍊表進行掃描即可。
因此,軟解析也會申請該 latch。
所以,不能說是簡單的硬解析的問題,一切都有可能 。
BTW, 筆者面試過很多人,其實更像看到的是分析問題的方法論,而不是使勁的猜…
為什麼呢?我們總會遇到很多經驗範圍之外的事情,怎麼可能猜出自己不知道的事情呢?
3. 找原因,Orale 就是這麼簡單!
既然長時間無法獲取 latch, 那麼是誰在持有 latch 呢?
需要說明的是,當無法獲取 latch:library cache 的時候,Oracle 在實現上,會将自己放到 latch 的等待着列表 waiter list 當中,那麼自然也就有一個對應的持有者列表,
這麼做的原因在于,當持有者使用完該 latch 後,到等待者列表中喚醒等待的進程即可。同時,Oracle 在做 SSD 的時候,就已經把持有者給打印到 trace 裡了。
搜索 "waiting for 70000006b9d8008 Childlibrary"
可以看到 “possible holder pid = 19ospid=10027060”,即持有者是 pid = 19 ospid=10027060
接下來,我們需要去看看 latch 持有者即 pid = 19 ospid=10027060 的進程在做什麼
4. 持有 latch 的人去哪了?
搜索 “ospid:10027060”,就可以看到 LATCH 持有者的進程的詳細信息了
包括進程名,在執行什麼 SQL,進程狀态是什麼,在等什麼資源…
可以看到:
Pid=19,spid=10027060 的進程,是 ORACLE 的一個 JOB SLVAE 進程 j001,
由于他在持有 latch, 導緻了很多進程需要等待,
holding (efd=5) 70000006b9d8008 Child library cache
乘勝追擊,進一步查看該進程在等什麼資源:
可以看到:
該進程對應的 SID 是 534,當前實際上并沒有在等待任何資源,因為 last wait 表示的是上一次的等待了。長時間持有 latch:library cache, 導緻 N 個進程登陸執行内部 SQL 的時候無法獲取 latch, 繼而無法登陸,但是,進程持有者 PID=19,SID=534,又沒有在等待任何資源,SQL:0 表示當前沒有在執行任何 SQL。
生無可戀了,那我怎麼知道進程持有者在做什麼呢,這還怎麼往下查呢…
提示:這裡請記住 latch 的持有者,SID 是 534,534!
5.陷入僵局
還記得麼,Oracle 有一套方法論,那麼方法論就是查看 call stack, 通過查看進程調用的函數軌迹,就可以判斷出來,當前進入了哪一種場景。
但是由于客戶一着急,收集的 SSD 的 level 不夠,因為沒有打印每個進程的 call stack!
這可如何是好啊, 難道問題要陷入僵局..
如果是你,接下來,會怎麼往下打這一場仗
6.細節決定成敗
如圖所示:
紅色加框部分顯示,該進程的狀态處于 DEAD 狀态!即持有 latch 的那個進程已經死掉了!
看到這裡:
有些朋友又要蒙圈了,“這是什麼情況?”
有些朋友可能已經開始有點想法了,心裡在嘿嘿樂…
沒錯,實際上,這已經設計到道和術的問題。
技術層面上,一路找到最終的阻塞者後,已經進行不下去了!
接下來,大家不妨停下來,思考一下:
原理層面呢?
學了那麼多體系架構的東西,怎麼用到生産問題中呢?
是否可以運用原理幫助解開這個數據庫挂起的問題呢?
我面試候選 DBA 的時候,喜歡問原理。
很多候選 DBA 答不上來的時候,總喜歡解釋道,而且是很坦然的解釋到:
不好意思,過去從來不關注原理, 熟練操作就可以了!
聽到這些回答,本人總會語重心長的讓對方做一道故障題,不掌握原理是不可能解開的,結果很顯然的,候選人自然答不上來,之後我會演示問題處理和分析過程,候選人往往都會重新定義對道和術的認知,孺子可教...
工程師熟練操作是基礎,,但是從中級工程師到高級工程師,再到資深工程師,深入原理是一道坎,能将原理熟練應用到實際分析中又是一道坎。什麼時候跨過坎了,層次也就不一樣了。很多 DBA 因為沒有人點撥,可能永遠過不了那道坎…
7. 振聾發聩的一問!
為什麼進程死掉了,但是進程還在持有 latch 資源不釋放?
PMON 做什麼去了?他是幹什麼吃的…
是的!這就是問題的關鍵!當聽到這麼一個振聾發聩的驚天一問時,恭喜你,跨過了一道坎!
如果已經提示到這個程度,依然無法發出這麼一個疑問,實在是!
8. 看看 PMON 在做什麼
搜索(PMON),就可以找到 SSD 中 PMON 進程的相關信息。如下所示:
可以看到:
PMON 正在等待 cursor:pin x,即申請模式為獨占,類型為 cursor 的 mutex
waiting for 'cursor: pin X'
該 mutux 的 IDN 是 idn=ad39e34, 即 hash 值
由于 PMON 被阻塞, 卡住了,因此自然沒有機會去清理死去進程所持有的 LATCH 了!
我們繼續真相又進了一步!
隻需要集中精力,需要繼續到底是是哪個進程,持有了 idn=ad39e34 的 mutex, 導緻 PMON 被長時間阻塞了,就可以解開問題的真相了!
接下來,大家不妨停下來,思考一下:
上圖中,但是 BLOCKING_SESS=0X0,這裡無法直接查看是誰阻塞了 PMON 進程。
那麼如果是你,你會怎麼往下查呢
……
9. 誰阻塞了 PMON
由于 PMON 進程以獨占方式申請
類型為 cursor 的 mutex 被阻塞,顯然該 MUTEX 正在被某個進程以獨享或獨占方式長時間持有。這顯然是不正常的。畢竟 MUTEX 是一種輕量級的資源。
接下來,我們在 TRACE 中搜索 "idn ad39e34 oper",結果如下所示
Mutex 70000003eec4be0(534, 0) idn ad39e34 oper GET_EXCL
Mutex 70000003eec4be0(534, 0) idn ad39e34 oper EXCL
可以看到:
該 MUTEX 上有兩個操作, OPER 即 Operation, 操作。
一個進程正在以獨占方式持有, 即 oper EXCL
另外一個進程正以獨占方式申請,oper GET_EXCL,Get 表示申請, 因此發生阻塞。該進程就是 PMON 進程。
紅色底紋部分的 534,就表示 MUTEX 的持有者,即 SID=534!
沒錯!SID=534 就是我們之前持有 latch:library cache 資源但已經死去的進程!
就是哪個等着被 PMON 清理的死去的進程!
10. 分析總結
綜合上述分析,總結如下:
1) N 個進程無法登陸,是因為無法獲得 latch:library cache 資源,該資源被一個死去的 SID=534 的進程持有了, 還沒釋放!
2) 按照原理,PMON 有義務去清理死去的 SID=534 的進程所持有的資源(latch 等).
3) 但是 PMON 隻有一個,PMON 正在等'cursor:pin X', 即以獨占方式申請類型為 cursor 的 mutex. 所以騰不出手來清理死去的 SID=534 的進程.
4) 正是 SID=534 持有 MUTEX,阻塞了 PMON !
假設說步驟 1,2 還合理的話,但是步驟 3 和 4 就毀三觀了!
總結起來就一句話,PMON 要去給死去的進程收屍,但是要獲得死去進程的同意!
這太不合理,太不科學了!為什麼會這樣呢…
很簡單,命中 BUG!
11. 輕松找 BUG
分析到這裡,掌握了問題的本質,那麼找 BUG 起來就很簡單了!
ORACLE 有一個強大的知識庫,記錄了全球客戶提交過的 CASE,裡面包含了 BUG 庫!
怎麼找到具體的 BUG 呢?
接下來不妨思考個 1 分鐘,如果是你,接下來你要怎麼定搜索關鍵字呢…
這裡,以 “pmon cursor dead” 做為關鍵字(其他關鍵字也可以),檢索 BUG。
很快,一個 BUG 的标題引起了注意:
Bug 8426816 PMON may hang cleaning up a dead process (rare)
點開 BUG,描述如下:
怎麼樣,看完了吧,這不就是我們這個問題麼!
an instance hang may result due to PMON getting
blocked when attempting to clean up a failed process.
從現象到問題本質完全吻合!版本 10.2.0.4 也完全吻合!
當 PMON 要以 X 模式即獨占模式申請 MUTEX(cursor:pin X 就是一種 mutex)去清理一個死去進程的時候,該 MUTEX 被死去進程持有!從而導緻了數據庫 HANG 的情況!
問題原因與經驗總結
故障過程總結:
1) SID=534 的進程在持有 latch:library cache 和 mutex 等資源的時候進程死去
2) PMON 有義務清理該進程所持有的資源,如 mutex
3) 由于命中 BUG 5377099 ,導緻 PMON 無法獲得 MUTEX,被死去的進程 534 阻塞
4) 因此 SID=534 的死去進程長時間持有 latch:library cache, 導緻其他用戶執行遞歸
SQL,無法被軟解析,繼而無法登陸,即數據庫出現了 HANG 的故障!
經驗總結:
1) 運維公式 = 快速收集系統即時狀态信息 恢複業務
2) 快速收集系統即時狀态信息的目的是做 RCA,根因分析,以便在大規模數據庫運維中可以預防其他數據庫也出現類似問題。
3) 不定期做補丁分析,發現嚴重的 BUG,提前預防。
4)技巧重要,原理更重要。
通過這樣一個案例,你不難發現,ORACLE 的 SSD 功能,真是強大的令人發指!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!