您好,登錄后才能下訂單哦!
前言:
時(shí)間一晃已經(jīng)來(lái)到了6月,技術(shù)人生系列文章已經(jīng)半年沒(méi)有更新了,在過(guò)去的半年時(shí)間里,我們技術(shù)人生系列文章的作者們一直奮戰(zhàn)在工作一線,同時(shí)不忘積累和總結(jié),為我們的文章提供更深厚的底蘊(yùn);如今,技術(shù)人生系列將攜中亦課堂正式回歸,依舊嚴(yán)謹(jǐn)深刻,生動(dòng)再現(xiàn)客戶現(xiàn)場(chǎng)處理問(wèn)題的點(diǎn)點(diǎn)滴滴,希望在傳遞更多知識(shí)點(diǎn)的同時(shí)給大家?guī)?lái)更多深度的思考。
在這里,首先感謝一直以來(lái)支持技術(shù)人生系列的小伙伴們,你們的支持與轉(zhuǎn)發(fā)是我們持續(xù)分享的動(dòng)力。
一、 問(wèn)題來(lái)了
某個(gè)周五的悠閑晚上,正在窗前思考人生的老k,接到了一個(gè)客戶的問(wèn)題,客戶現(xiàn)場(chǎng)的DBA處理了有一些日子了,準(zhǔn)備在周末的時(shí)間窗口重啟來(lái)解決該問(wèn)題,不過(guò)客戶還是很謹(jǐn)慎的囑咐說(shuō),估計(jì)重啟后該問(wèn)題可能就沒(méi)法重現(xiàn)了,我們需要在重啟前找到問(wèn)題的觸發(fā)根因,避免再次出現(xiàn)此類問(wèn)題。
那么具體問(wèn)題是什么呢?客戶描述的信息如下:
應(yīng)用在執(zhí)行某些SQL的時(shí)候經(jīng)常出現(xiàn)ORA-01410的錯(cuò)誤,但是這樣的錯(cuò)誤只是偶爾出現(xiàn),手動(dòng)執(zhí)行的時(shí)候并不一定能遇到,因?yàn)樯婕暗降谋砜赡苡卸鄠€(gè),經(jīng)過(guò)前期分析,懷疑是內(nèi)存錯(cuò)亂導(dǎo)致的,預(yù)計(jì)在下個(gè)周末進(jìn)行操作系統(tǒng)重啟來(lái)解決該問(wèn)題,目前可以試著從數(shù)據(jù)庫(kù)層面來(lái)分析該問(wèn)題,看能不能有什么發(fā)現(xiàn);
從跟客戶的交流來(lái)看,似乎已經(jīng)被這個(gè)問(wèn)題折磨了很久,而現(xiàn)在已經(jīng)對(duì)分析這個(gè)問(wèn)題的原因不報(bào)太大的希望,只是報(bào)著試一試的心態(tài)來(lái)分析這個(gè)問(wèn)題;
客戶只是報(bào)著試一試的心態(tài)給我們轉(zhuǎn)交了這個(gè)問(wèn)題,但是我們作為服務(wù)商,就必須以全力以赴的態(tài)度來(lái)解決客戶的問(wèn)題。
二、 摸清情況
要盡快解決問(wèn)題,只能遠(yuǎn)程分析,于是我聯(lián)系到客戶的接口DBA,通過(guò)遠(yuǎn)程連接到客戶的服務(wù)器,了解了相關(guān)環(huán)境,分析問(wèn)題;具體情況如下:
操作系統(tǒng):REDHAT 6
數(shù)據(jù)庫(kù):oracle 10.2.0.5 單節(jié)點(diǎn)
具體現(xiàn)象:某些表的訪問(wèn)報(bào)ORA-01410,很明顯的對(duì)于一個(gè)SQL語(yǔ)句,如果在SQL中去掉該表,整個(gè)SQL就不會(huì)報(bào)錯(cuò);另外存在這種情況的表有多個(gè);該現(xiàn)象不會(huì)一直出現(xiàn),偶爾會(huì)出現(xiàn);
首先跟客戶DBA溝通,拿到了幾個(gè)存在該問(wèn)題的SQL,直接執(zhí)行這些語(yǔ)句,在試驗(yàn)很多次后,確實(shí)遇到了好幾次錯(cuò),特別是執(zhí)行時(shí)間較長(zhǎng)的SQL;
選取其中較簡(jiǎn)單的一個(gè)語(yǔ)句,其語(yǔ)句和執(zhí)行計(jì)劃如下:
這個(gè)SQL語(yǔ)句中,出現(xiàn)問(wèn)題的表是XXXstatelog,這個(gè)表比較小,只有60M;
而出現(xiàn)的ORA-1410錯(cuò)誤是什么呢?
[oracle@test10g ~]$ oerr ora 1410
01410, 00000, "invalid ROWID"
// *Cause:
// *Action:
ORA-1410錯(cuò)誤是因?yàn)橛袩o(wú)效的ROWID,ORACLE并未提示出現(xiàn)該類情況的可能原因;
三、 交流與搜索
現(xiàn)在基本情況了解了,不過(guò)客戶DBA已經(jīng)分析了有一些時(shí)間了,而且他們更了解整體的應(yīng)用、硬件以及相關(guān)的變化情況,在接手現(xiàn)場(chǎng)問(wèn)題的時(shí)候,我都習(xí)慣多與客戶DBA進(jìn)行更多的溝通,一方面可以借鑒他們的已有經(jīng)驗(yàn),避免重復(fù)發(fā)明輪子,另一方面,旁觀者清,也許也可以給他們指出一些紕漏之處,發(fā)現(xiàn)問(wèn)題的關(guān)鍵;總之,充分利用已有的資源來(lái)快速分析問(wèn)題,更何況網(wǎng)絡(luò)時(shí)斷時(shí)續(xù)的,相關(guān)操作還需要客戶幫忙執(zhí)行和收集。
問(wèn):最近有做過(guò)什么變化嗎?
答:數(shù)據(jù)庫(kù)并未做什么調(diào)整,對(duì)于應(yīng)用版本的調(diào)整了解的并不多;
問(wèn):應(yīng)用端除了這個(gè)報(bào)錯(cuò)外,還有什么其他的問(wèn)題嗎,如wrong result之類的?
答:并沒(méi)有這樣的反饋;
問(wèn):這樣的報(bào)錯(cuò)有什么規(guī)律嗎?
答:只知道出現(xiàn)這樣情況的表又五六個(gè),并沒(méi)有發(fā)現(xiàn)時(shí)間上、頻度上有什么特別的規(guī)律;通常失敗了的操作,再執(zhí)行一次,好像就并沒(méi)有什么問(wèn)題。
看來(lái)并沒(méi)有更多信息,那先思考一下吧;再看看這個(gè)報(bào)錯(cuò):
[oracle@test10g ~]$ oerr ora 1410
01410, 00000, "invalid ROWID"
// *Cause:
// *Action:
兩個(gè)關(guān)鍵信息: ROWID和invalid ;
首先,什么時(shí)候會(huì)用到ROWID呢,通常來(lái)說(shuō),ROWID是一個(gè)偽列,并不存在于表的數(shù)據(jù)塊中,似乎只有索引的葉子塊中才會(huì)存儲(chǔ)ROWID用以定位數(shù)據(jù)位置;
另外,INVALID,似乎意味著存儲(chǔ)在索引中的rowid出現(xiàn)了異常,或者在讀到內(nèi)存中后出現(xiàn)了混亂?
沒(méi)有更多信息的情況下,不如借鑒MOS上已有的經(jīng)驗(yàn),看看導(dǎo)致ORA-1410的現(xiàn)象都有哪些情況,于是找到了一篇解釋該類錯(cuò)誤的文章:
其中描述了ORA-1410的觸發(fā)情況:
從這里給出的一系列描述看,主要可能的原因包括: 數(shù)據(jù)塊損壞、索引塊損壞、內(nèi)存損壞、DDL操作導(dǎo)致的異常以及各種bug;
從我們遇到的情況看,數(shù)據(jù)塊/索引塊的損壞似乎不存在,因?yàn)槎啻螆?zhí)行并不會(huì)總是出現(xiàn)錯(cuò)誤;
在先不考慮bug的情況下,就只有DDL操作或者內(nèi)存異常的情況了,那么是不是DDL操作導(dǎo)致的問(wèn)題呢?
四、思考與推斷
目前看到的這篇MOS文檔講述的還算比較全面,于是我先發(fā)送給客戶DBA討論;
然而,客戶DBA表示,已經(jīng)仔細(xì)閱讀過(guò)這篇文檔了,而且他們跟應(yīng)用溝通過(guò),出現(xiàn)問(wèn)題的時(shí)段應(yīng)該是不會(huì)有DDL操作,只會(huì)在晚上的固定一個(gè)時(shí)間段存在一些TRUNCATE操作;另外,他們也在自己的環(huán)境也測(cè)試過(guò)了,truncate并沒(méi)有導(dǎo)致ORA-1410的報(bào)錯(cuò),而且以過(guò)往的經(jīng)驗(yàn)來(lái)看,以前遇到過(guò)的truncate導(dǎo)致的查詢錯(cuò)誤報(bào)的都是ORA-8103;所以,這里客戶認(rèn)為可能還是內(nèi)存的問(wèn)題或者ORACLE的bug導(dǎo)致的;看來(lái)客戶DBA還是很有經(jīng)驗(yàn)的。
對(duì)于客戶的看法,我是有幾分認(rèn)同的:
1. ORA-1410我似乎很少遇到過(guò),以前遇到過(guò)都是索引異常的情況;
2. 另外truncate導(dǎo)致SQL執(zhí)行報(bào)錯(cuò)的情況通常報(bào)的是ORA-8103,對(duì)象不存在;
3. 如果真的是沒(méi)有意識(shí)到的truncate操作,那前端業(yè)務(wù)可能已經(jīng)受到影響了;
這樣好像不應(yīng)該是truncate導(dǎo)致的,但是現(xiàn)象上時(shí)好時(shí)壞又是怎么產(chǎn)生的呢?如果真的是內(nèi)存中的異常,那它是怎么好的呢?它的觸發(fā)條件是什么呢?
趁著與客戶網(wǎng)絡(luò)斷斷續(xù)續(xù)的情況,我開始了獨(dú)自思考。
根據(jù)mos 文檔的描述問(wèn)題出現(xiàn)的原因主要有幾類:
1. 數(shù)據(jù)庫(kù)中存在著頻繁的DDL 語(yǔ)句。
2. 某個(gè)索引或者數(shù)據(jù)塊出現(xiàn)了損壞,也就是壞塊導(dǎo)致的問(wèn)題
3. 硬件層面,例如:內(nèi)存出現(xiàn)了問(wèn)題
4. Oracle 的bug
再仔細(xì)回顧一下這個(gè)問(wèn)題的現(xiàn)象逐一思考各種可能原因:
1. DDL語(yǔ)句導(dǎo)致的,但是用戶已經(jīng)確認(rèn)了DDL語(yǔ)句只會(huì)在特定的時(shí)間執(zhí)行。
2. 某個(gè)數(shù)據(jù)塊或者索引塊損壞,這個(gè)可以通過(guò)下面的語(yǔ)句來(lái)進(jìn)行判斷
SQL>analyze table <table_name> validate structure cascade;
在和用戶確認(rèn)過(guò)之后,發(fā)現(xiàn)著命令并沒(méi)有返回壞塊相關(guān)的信息,基本可以排除壞塊的可能。
3. 內(nèi)存層面的問(wèn)題,如果是內(nèi)存層面的問(wèn)題,更大的可能性是當(dāng)訪問(wèn)某個(gè)表的某一些數(shù)據(jù)塊的時(shí)候會(huì)出現(xiàn)問(wèn)題。而且硬件工程師也確認(rèn)了,內(nèi)存并沒(méi)有問(wèn)題,所以,也基本上可以排除,內(nèi)存出現(xiàn)問(wèn)題的可能性。
4. Oracle 的 bug,在 mos上進(jìn)行了一些搜索之后,也沒(méi)有找到類似的問(wèn)題。
五、 測(cè)試與模擬
經(jīng)過(guò)上面的思考后,我還是認(rèn)為truncate操作導(dǎo)致異常的可能性更大,對(duì)于這樣的case如果能重現(xiàn)出來(lái),相信會(huì)非常有說(shuō)服力,嗯,這樣的重現(xiàn)應(yīng)該是比較簡(jiǎn)單的,不如直接重現(xiàn);
于是,我開始在自己的測(cè)試環(huán)境,同樣是10g數(shù)據(jù)庫(kù),Redhat linux環(huán)境中來(lái)重現(xiàn),實(shí)現(xiàn)操作如下:
1. 創(chuàng)建表,生成更多數(shù)據(jù),創(chuàng)建索引
create table test0611 as select * from dba_objects ;
insert into test0611 as select * from test0611;--執(zhí)行多次
create index T0611_IDX1 on test0611(object_id);
2. 構(gòu)造通過(guò)索引訪問(wèn)數(shù)據(jù)的語(yǔ)句
因?yàn)閞owid只有在索引中才會(huì)用到,我們這里使用hint的方式,讓SQL執(zhí)行過(guò)程中先訪問(wèn)索引,再通過(guò)索引返表,這是一個(gè)比較差的執(zhí)行計(jì)劃這個(gè)SQL執(zhí)行時(shí)間會(huì)比較長(zhǎng);
3. 在進(jìn)行上述查詢的過(guò)程中,我們?cè)诹硪粋€(gè)會(huì)話中執(zhí)行trauncate操作
truncate table test0611;
4. 觀察第2步的查詢操作,確認(rèn)是否出現(xiàn)報(bào)錯(cuò)
先后執(zhí)行了幾次上述模擬案例測(cè)試,并未能重現(xiàn)ORA-1410的錯(cuò)誤或者其他錯(cuò)誤,查詢正常完成。問(wèn)題似乎陷入了僵局,難道truncate 語(yǔ)句真的不是問(wèn)題的原因? 我們反過(guò)來(lái)想一下,如果要推翻自己的分析,最直接的辦法就是拿到更多的證據(jù)來(lái)證明自己的分析是錯(cuò)誤的。那就再來(lái)搜集更多的信息吧。
六、 意外發(fā)現(xiàn)與解決問(wèn)題
在自己的環(huán)境沒(méi)能快速重現(xiàn)出問(wèn)題來(lái),看來(lái)還得到生產(chǎn)環(huán)境繼續(xù)挖掘其他線索,爭(zhēng)取在重啟前搜集足夠的信息;
在查看的過(guò)程中,意外發(fā)現(xiàn),這個(gè)環(huán)境上竟然部署了OGG(oracle goldengate),而它是作為源端將整個(gè)SCHEMA的表同步到目標(biāo)端的ORACLE實(shí)例,這似乎給定位問(wèn)題帶來(lái)了轉(zhuǎn)機(jī): 如果是內(nèi)存層面的異常,理論上是不會(huì)傳導(dǎo)到ogg目標(biāo)端的ORACLE實(shí)例上的;而如果是表本身或者索引本身的問(wèn)題,那么在ogg目標(biāo)端的ORACLE實(shí)例上也就應(yīng)該能重現(xiàn);
接下來(lái),我們就在ogg目標(biāo)數(shù)據(jù)庫(kù)上執(zhí)行相關(guān)查詢,經(jīng)過(guò)半個(gè)小時(shí)的測(cè)試發(fā)現(xiàn),同樣的語(yǔ)句在ogg目標(biāo)數(shù)據(jù)庫(kù)上也會(huì)報(bào)錯(cuò),不過(guò)與生產(chǎn)環(huán)境不同的是,報(bào)錯(cuò)信息是ORA-8103;
[oracle@11g dmp]$ oerr ora 8103
08103, 00000, "object no longer exists"
// *Cause: The object has been deleted by another user since the operation
// began, or a prior incomplete recovery restored the database to
// a point in time during the deletion of the object.
// *Action: Delete the object if this is the result of an incomplete
// recovery.
ORA-8103就比較熟悉了,通常是因?yàn)閷?duì)象被drop掉或者truncate掉導(dǎo)致的;同時(shí),我們發(fā)現(xiàn)目標(biāo)數(shù)據(jù)庫(kù)的版本是11g的數(shù)據(jù)庫(kù),頓時(shí)我們覺(jué)得問(wèn)題就簡(jiǎn)單多了,在11g數(shù)據(jù)庫(kù)中,存在一個(gè)參數(shù)enable_ddl_logging來(lái)控制是否將DDL操作記錄到alert日志中,而這源端的10g數(shù)據(jù)庫(kù)時(shí)沒(méi)有這個(gè)功能的;
于是,我們?cè)谀繕?biāo)端數(shù)據(jù)庫(kù)實(shí)例中調(diào)整了該參數(shù)后,alert日志中很快就捕捉到了truncate的信息;
Tue Jun 01 20:11:18 2018
ALTER SYSTEM SET enable_ddl_logging=TRUE SCOPE=BOTH;
Tue Jun 01 20:16:34 2018
truncate table XXXstatelog
至此,似乎就真相大白了,正是應(yīng)用在代碼里加了truncate的操作,比較頻繁的truncate操作導(dǎo)致相關(guān)表的查詢出現(xiàn)報(bào)錯(cuò)中斷,接下來(lái)客戶DBA要做的就是和開發(fā)溝通其truncate操作的目的,并對(duì)此進(jìn)行相應(yīng)的調(diào)整;
將頻繁的truncate操作去掉,改成定期的truncate操作后,便沒(méi)有再在業(yè)務(wù)時(shí)間段出現(xiàn)ORA-1410或者ORA-8103的錯(cuò)誤了,這樣事情就告一段落了。
七、 研究與重現(xiàn)
客戶的問(wèn)題是解決了,但是新的疑惑又開始縈繞在我的腦中,只不過(guò)現(xiàn)在沒(méi)有客戶的壓力,沒(méi)有時(shí)間的緊迫性,可以靜下心來(lái)慢慢研究這個(gè)問(wèn)題:
1. 為什么在我的環(huán)境中測(cè)試,truncate并沒(méi)有影響到select操作,而客戶環(huán)境中的truncate操作卻影響到了select操作,那么這種區(qū)別來(lái)自于哪呢?
2. 對(duì)于10g環(huán)境報(bào)錯(cuò)信息為ORA-1410,而對(duì)于11g環(huán)境,則報(bào)的是ORA-8103,這兩者的區(qū)別又是什么呢?
要回答第一個(gè)問(wèn)題,我們還是先要了解一下truncate操作對(duì)表/索引到底做了什么:
1) 對(duì)于普通的堆表來(lái)說(shuō),truncate操作只是截?cái)嗔吮砗退饕?,主要是修改了?shù)據(jù)字典信息和段頭信息;
2) 對(duì)于我們簡(jiǎn)單的通過(guò)索引訪問(wèn)表數(shù)據(jù)的情況,在查詢過(guò)程中執(zhí)行truncate了后,truncate修改了段頭信息,而我們需要訪問(wèn)的具體的索引塊和數(shù)據(jù)塊都沒(méi)有發(fā)生改變情況下,自然是不會(huì)發(fā)生報(bào)錯(cuò)的;
3) 而我們將truncate的數(shù)據(jù)塊覆蓋掉,或者讓我們的查詢需要訪問(wèn)到段頭信息時(shí),ORA-1410或者ORA-8103的報(bào)錯(cuò)就出來(lái)了;
理解了上面的幾點(diǎn),我們?cè)賮?lái)重現(xiàn)錯(cuò)誤,就很簡(jiǎn)單了;下面我們來(lái)構(gòu)建幾個(gè)重現(xiàn)場(chǎng)景:
首先構(gòu)造兩張表,其中T06182表比較大,T06183表比較小,在object_id列上存在索引:
構(gòu)造查詢用的語(yǔ)句:
測(cè)試場(chǎng)景一:
一個(gè)會(huì)話執(zhí)行簡(jiǎn)單的查詢,另一個(gè)會(huì)話在查詢期間執(zhí)行了truncate操作,truncate操作完成后,查詢能繼續(xù)完成而沒(méi)有報(bào)錯(cuò);
(注:truncate的完成時(shí)間是11:13:59,在查詢過(guò)程中,查詢未受影響)
測(cè)試場(chǎng)景二:
一個(gè)會(huì)話執(zhí)行簡(jiǎn)單的查詢,另一個(gè)會(huì)話在查詢期間執(zhí)行truncate操作,truncate操作完成后,繼續(xù)執(zhí)行flush buffer cache 的操作,出現(xiàn)ORA-1410報(bào)錯(cuò);
(注:truncate完成時(shí)間是11:22:06,flush buffer_cache的開始時(shí)間是11:22:15,同期查詢報(bào)錯(cuò))
測(cè)試場(chǎng)景三:
一個(gè)會(huì)話執(zhí)行簡(jiǎn)單的查詢,另一個(gè)會(huì)話在查詢期間執(zhí)行truncate操作,truncate操作完成后,繼續(xù)執(zhí)行 insert操作,出現(xiàn)ORA-1410報(bào)錯(cuò);
(注:truncate完成時(shí)間是11:20:05,insert執(zhí)行時(shí)間是11:20:16,同期查詢報(bào)錯(cuò),truncate后插入數(shù)據(jù),extent被重用,導(dǎo)致訪問(wèn)數(shù)據(jù)時(shí)報(bào)錯(cuò))
對(duì)于第二個(gè)問(wèn)題,其實(shí)在充分理解了ORA-1410和ORA-8103的錯(cuò)誤后,我們也就能知道他們的共同之處了,看起來(lái)只是在10g報(bào)ORA-1410,而11g報(bào)ORA-8103;
可以看到,同樣的case,在11g數(shù)據(jù)庫(kù)環(huán)境中出現(xiàn)的是ORA-8103錯(cuò)誤;
而且MOS上還可以找到類似的一些文章來(lái)說(shuō)明這個(gè)問(wèn)題:
小 結(jié)
從整個(gè)問(wèn)題來(lái)看,其實(shí)就是一系列truncate引發(fā)的問(wèn)題,在最開始階段懷疑到最后確認(rèn)問(wèn)題,中間走了一些彎路,導(dǎo)致問(wèn)題的分析顯得有些復(fù)雜;馬后炮的來(lái)看,其實(shí)如果懷疑到truncate,我們直接去查看對(duì)象的last_ddl_time和DATA_OBJECT_ID,就可以直接的定位了;亦或者在處理問(wèn)題時(shí)沒(méi)有那么緊張,仔細(xì)閱讀MOS 的1410.1文檔,也能很快的確定幾個(gè)方向,并逐一去確認(rèn);然而,這正是高壓力下實(shí)時(shí)處理問(wèn)題和事后分析的區(qū)別所在,慶幸的是,正好因?yàn)檫@個(gè)問(wèn)題還算費(fèi)了一些時(shí)間,反而讓我進(jìn)一步試圖去重現(xiàn)問(wèn)題,反思整個(gè)過(guò)程,進(jìn)而有了更多發(fā)現(xiàn),總結(jié)一下,也是一線工程師的一些必備技能,寫給自己也分享給大家:
1. 對(duì)于原理的理解,在解決問(wèn)題特別是想重現(xiàn)故障的時(shí)候,極為重要,否則很有可能出現(xiàn)重現(xiàn)達(dá)不到預(yù)期效果而導(dǎo)致錯(cuò)誤結(jié)論的情況;
2. 對(duì)于實(shí)時(shí)處理問(wèn)題,即使壓力再大,時(shí)間再趕,對(duì)于不了解的細(xì)節(jié),對(duì)于未讀過(guò)的文章,還是需要靜下心來(lái)仔細(xì)閱讀,否則就有可能錯(cuò)失那個(gè)讓你一蹴而就的知識(shí)點(diǎn);
3. 試著去重現(xiàn)你遇見的問(wèn)題,這會(huì)比解決問(wèn)題讓你印象更加深刻。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。