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