您好,登錄后才能下訂單哦!
線上的生產(chǎn)系統(tǒng),出現(xiàn)故障是大家都不愿意看到的。
但是當(dāng)出現(xiàn)故障,造成業(yè)務(wù)影響,涉及事后追責(zé)的時候,
運(yùn)維與開發(fā),運(yùn)維各團(tuán)隊(duì)之間,很容易出現(xiàn)相互推諉、各說各話的情況,
畢竟,故障責(zé)任這個鍋,誰也不想背!
解決這類問題的最有效途徑是什么呢?
答案是根因分析!
通常做到根因分析后,很容易重現(xiàn)并模擬故障,一切都會變得更加容易。
小 y 今天為大家分享這么一個案例 :
一支批量程序跑了好幾年了,都好好的。
在沒有掉電的情況下,突然某天再也跑不過去了!現(xiàn)象是數(shù)據(jù)庫出現(xiàn)了壞塊。
這個時候,有點(diǎn)“經(jīng)驗(yàn)”的運(yùn)維團(tuán)隊(duì)可能不自覺的哀嘆,有點(diǎn)想主動背這個鍋了。
別著急!問題分析,切忌遇到問題淺嘗輒止,或者不要著急說,已經(jīng)沒法往下查了,
小 y 今天帶著你,讓我們一起來一次壞塊根因分析之旅吧。
同時,文章最后會給出一個具體的 潛在的導(dǎo)致壞塊的風(fēng)險提示 ,讀完本文,你就會發(fā)現(xiàn),這個隱患可能長期潛伏,擇日爆發(fā)。 希望大家早了解,早預(yù)防,避免踩坑。
Oracle 數(shù)據(jù)庫問題,還是找不到原因?
不妨找中亦科技試試,我們將盡最大努力為您找到導(dǎo)致故障和性能問題的根本原因。
問題來了!
日期
:
ORA-08102: 未找到索引關(guān)鍵字, 對象號 64560, 文件 4, 塊 192411 (2)
即索引和表數(shù)據(jù)不一致
2
常見的
ORA-8102
的原因有哪些呢?
?
IO
寫丟失導(dǎo)致的表和索引數(shù)據(jù)不一致
?
ORACLE BUG
導(dǎo)致的表和索引不一致
可以刪除索引重建么?--第一次頭腦風(fēng)暴
我相信絕大部分專家的解決方法:
都是以表中數(shù)據(jù)為準(zhǔn),把索引刪除再創(chuàng)建!
但是在沒找到問題原因之前,
刪除并重建索引的做法是不負(fù)責(zé)任的做法
可能無法根本解決問題,以后很可能還會多次復(fù)發(fā)。
舉例來說,重建索引是以表數(shù)據(jù)為準(zhǔn),但是既然表和索引的數(shù)據(jù)不一致,為什么不能是以索引數(shù)據(jù)為準(zhǔn)來修正表的數(shù)據(jù)呢?比如當(dāng)出現(xiàn)“表的寫
IO
丟失,但是索引的寫
IO
成功”的情況時,就不應(yīng)該以表為基準(zhǔn)重建索引!所以,雖然重建索引可能會解決問題,但是卻可能導(dǎo)致業(yè)務(wù)數(shù)據(jù)丟失和破壞。
因此不可以盲目的按照索引方式來處理該問題,可能會導(dǎo)致數(shù)據(jù)丟失和破壞!
這個系統(tǒng)存儲的是金融數(shù)據(jù),我需要更謹(jǐn)慎。在沒確定問題原因前,我暫時不會做出任何變更和調(diào)整的動作。
那么真的是出現(xiàn)了壞塊么?我們需要深入分析,了解事情背后的真相!
思考時間
--
壞塊根因分析該如何繼續(xù)
壞塊原因該怎么分析?
到這里,讀者朋友們不妨思考一下。
如果是你,你會怎么往下查壞塊的成因呢?
別著急,多思考個三五分鐘,問題原因就在后面,什么時候往下翻,由你決定…
.........
.........
.........
.........
.........
.........
.........
根因分析過程
首先獲取報錯的SQL
查看
alert
日志中出現(xiàn)的
ORA-8102
的
trace,
搜索
current sql,
可以發(fā)現(xiàn),
ORA-8102
錯誤是咋執(zhí)行下列
SQL
語句時出現(xiàn)的
可以看到,該
SQL
實(shí)現(xiàn)的功能很簡單:
將
TAB_XXX
表中滿足條件的
BANKID
字段從
舊值
更新為
新值
獲取索引的定義
根據(jù)報錯信息中的對象號,檢索
dba_objects,
可知出現(xiàn)問題的索引是
INDEX_TAB_XXX_FUNC ,
進(jìn)一步獲取該索引的定義,如下所示:
可以看到
:
這是一個特殊的索引,是一個使用了
用戶自定義函數(shù)
創(chuàng)建的
函數(shù)索引
,這與我們通常使用到的函數(shù)索引
trim
、
to_number
等內(nèi)置函數(shù)的函數(shù)索引有點(diǎn)不一樣。
獲
取自定義函數(shù)的定義
這里可以看到,用到了用戶自定義的函數(shù),自定義的函數(shù)代碼如下:
這個函數(shù)實(shí)現(xiàn)的是
:
通過傳入一個機(jī)構(gòu)號,獲取
TAB_ANOTHER_XXX
表當(dāng)中的一級行的機(jī)構(gòu)號。
真相逐漸浮出水面
到這里,小y腦子過了一次,基本上知道了問題的真相。讀者朋友們不妨思考一下,問題真相是什么呢?
別著急,多思考個三五分鐘,問題真相就在后面,什么時候往下翻,由你決定…
……
……
……
……
……
……
真相大白——成功反轉(zhuǎn)
到這里,小y終于想通了,
這不是壞塊,不是數(shù)據(jù)庫的一個BUG,恰恰想法,而是應(yīng)用程序的一個BUG!
當(dāng)應(yīng)用程序要執(zhí)行下列SQL時
需要注意的是
:
報錯
SQL
更新的表是
TAB_XXX
表,而函數(shù)索引中的自定義函數(shù)是取
TAB_ANOTHER_XXX
表的值,
這是兩張不同的表,需要引起注意!
另外,函數(shù)指定了
deterministic
屬性,即對于一個固定的
bankid,
函數(shù)的返回值,
從業(yè)務(wù)上要求都是固定的、唯一的
。
如果業(yè)務(wù)層面發(fā)生了變化,對于同一個
bankid,
他的
top
發(fā)生了變化,那必然會導(dǎo)致表和索引數(shù)據(jù)不一致!
具體來說,問題發(fā)生過程如下
:
由于要更新bankid字段,而該字段上存在索引,因此ORACLE除了要更新數(shù)據(jù)BLOCK中的bankid字段外,由于bankid字段被更新,而bankid字段上又存在一個用戶自定義函數(shù)索引,因此需要更新函數(shù)索引中的鍵值。
為此,oracle首先要找到bankid=:b1在函數(shù)索引中的位置,即找到keyvalue= FUNC_GET_TOP(:b1),并且該索引條目中的rowid=被修改的數(shù)據(jù)塊中的行。
如果此時運(yùn)行FUNC_GET_TOP(:b1)函數(shù)的結(jié)果與創(chuàng)建索引時運(yùn)行FUNC_GET_TOP(:b1)后計(jì)算的結(jié)果不一致,那么是肯定找不到滿足索引數(shù)據(jù)的。
即函數(shù)索引中的函數(shù)值是不確定的,那么顯然ORACLE是找不到” keyvalue= FUNC_GET_TOP(:b1)&索引entry中的rowid=被修改的數(shù)據(jù)塊中的行”的。那么就會報ORA-08102:未找到索引關(guān)鍵字。
這里FUNC_GET_TOP函數(shù)是在另外一張TAB_ANOTHER_XXX表中根據(jù)bankid取top_bank_id字段的值,如果bankid=:b1的top_bank_id值發(fā)生了改變,那么FUNC_GET_TOP(:b1)的結(jié)果就發(fā)生了改變,那么對于一個傳入的bankid,兩次計(jì)算出來的結(jié)果是不確定的,即索引鍵值是不固定的。就不滿足函數(shù)索引中對自定義函數(shù)要求deterministic屬性(對于每個輸入,函數(shù)的輸出結(jié)果是固定唯一的)。
這就是這個故障的本質(zhì)原因
。
為什么以前不出現(xiàn)??
下屬某市級行原本屬于某省行(一級行),但是由于該市級行業(yè)務(wù)量大,后來成為了一級行,意味著網(wǎng)點(diǎn)機(jī)構(gòu)的一級行從省級行變成了市級行。這是在年初時候就調(diào)整了的。意味著表
TAB_ANOTHER_XXX發(fā)生了變化,但是TAB_XXX表還沒有變化
在故障日(半年后)中,市級行的下屬行第一次進(jìn)行了機(jī)構(gòu)撤并,即修改
bank_id,
此時
TAB_XXX
表開始變化
,因此需要同步維護(hù)索引,即修改函數(shù)索引中的對應(yīng)鍵值,也就觸發(fā)了這個問題。年初調(diào)整了
bankid
的
top_bank_id,
但那時還不需要維護(hù)索引,因此年初調(diào)整機(jī)構(gòu)不會引發(fā)問題。過了半年多,才出現(xiàn)問題。
問題模擬重現(xiàn)
原理解釋:
當(dāng)把
tb1
表的
id=1
更新為
id=12
時,數(shù)據(jù)塊上已經(jīng)完成了更新(執(zhí)行計(jì)劃為全表掃描,
id
字段上無索引),此時還需要更新
id
字段上的函數(shù)索引
fc1(id)
而要更新
id
字段上的函數(shù)索引,需要先執(zhí)行
fc1(1)
做為鍵值去查找,結(jié)果顯然是
111(
新的
top_id),
此時索引中顯然找不到“鍵值
=111
,
rowid
指向數(shù)據(jù)庫
slot
的一個
entry
”,因此報
ORA-8102
,未找到索引關(guān)鍵字。表現(xiàn)上是數(shù)據(jù)與索引不一致,
實(shí)則是業(yè)務(wù)上無法保證自定義函數(shù)索引返回固定值導(dǎo)致。
問題解決
綜上所述,因?yàn)榱私獾恼麄€問題的發(fā)生過程,那么重建索引是安全的!
不會導(dǎo)致數(shù)據(jù)的丟失和破壞!
在與應(yīng)用團(tuán)隊(duì)以及開發(fā)項(xiàng)目組反饋了問題的本質(zhì)原因后,應(yīng)用團(tuán)隊(duì)組織人員在測試環(huán)境進(jìn)行了測試,臨時修改了某些機(jī)構(gòu)的頂級機(jī)構(gòu)號,再次重提批量,問題得到重現(xiàn),報錯
ORA-8102
。
由于短期不會再有更新一級行的變更,因此臨時解決方式是重建索引。
后面如果還有類似修改一級行的需求,則從流程上再次重建索引。技術(shù)上,去掉該函數(shù)索引,使用子查詢的方式代替即可。
最后,應(yīng)用團(tuán)隊(duì)提交了重建索引的變更,批量順利完成
,
問題得到圓滿解決
,
并且找到了根因。
風(fēng)險提示
風(fēng)險提示:
使用自定義函數(shù)索引時,需要保證,對于自定義函數(shù)的一個確定的輸入值
I_1
,他的輸出值
O_1
從業(yè)務(wù)上必須保證是唯一的。否則會導(dǎo)致索引和數(shù)據(jù)不一致,
ORA-8102
的錯誤。該類問題比較隱蔽,可能會潛伏一段時間,當(dāng)對于自定義函數(shù)的一個確定的輸入值
I_1
,他的輸出值從
O_1
變?yōu)?
O_2
時,問題出現(xiàn)。
因此,我們建議:
1)
對使用用戶自定義函數(shù)索引的情況進(jìn)行排查,并與應(yīng)用團(tuán)隊(duì)一起,從業(yè)務(wù)上確定對于一個傳入值,自定義函數(shù)是否可以返回固定的、唯一的值。
2)
將自定義函數(shù)索引的風(fēng)險傳遞到開發(fā)中心,進(jìn)行普及,在開發(fā)階段杜絕該類問題。
如何檢查自己的系統(tǒng)中是否存在類似問題呢
1
首先檢查所有應(yīng)用程序的函數(shù)索引
輸出結(jié)果如下所示
,
其中的
DATA_DEFAULT
字段就是函數(shù)索引的定義,對
trim/to_number/to_char
等自定義函數(shù)進(jìn)行排除后,就是自定義函數(shù)索引
2
然后使用下列命令來獲取函數(shù)定義
執(zhí)行時,需將上述命令中的函數(shù)名和用戶替換為上述查詢分析結(jié)果中的函數(shù)和用戶。
3
最后對自定義函數(shù)的內(nèi)容進(jìn)行梳理
與應(yīng)用團(tuán)隊(duì)確認(rèn)該函數(shù)是否可以保證對于每個輸入,函數(shù)的返回值是固定的、唯一的。如果無法確認(rèn),則需要進(jìn)行整改,避免后續(xù)業(yè)務(wù)變化導(dǎo)致的故障,影響業(yè)務(wù)連續(xù)性。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。