溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

發(fā)布時間:2020-08-04 18:54:27 來源:ITPUB博客 閱讀:126 作者:記錄每一次錯誤 欄目:關(guān)系型數(shù)據(jù)庫

線上的生產(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ù)


壞塊原因該怎么分析?

到這里,讀者朋友們不妨思考一下。

如果是你,你會怎么往下查壞塊的成因呢?

 

別著急,多思考個三五分鐘,問題原因就在后面,什么時候往下翻,由你決定…

.........

.........

.........

.........

.........

.........

.........

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

根因分析過程


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

首先獲取報錯的SQL

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期



查看 alert 日志中出現(xiàn)的 ORA-8102 trace, 搜索 current sql, 可以發(fā)現(xiàn), ORA-8102 錯誤是咋執(zhí)行下列 SQL 語句時出現(xiàn)的

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

可以看到,該 SQL 實(shí)現(xiàn)的功能很簡單:

TAB_XXX 表中滿足條件的 BANKID 字段從 舊值 更新為 新值


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

獲取索引的定義

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期


根據(jù)報錯信息中的對象號,檢索 dba_objects, 可知出現(xiàn)問題的索引是 INDEX_TAB_XXX_FUNC , 進(jìn)一步獲取該索引的定義,如下所示:


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

可以看到 :

這是一個特殊的索引,是一個使用了 用戶自定義函數(shù) 創(chuàng)建的 函數(shù)索引 ,這與我們通常使用到的函數(shù)索引 trim 、 to_number 等內(nèi)置函數(shù)的函數(shù)索引有點(diǎn)不一樣。


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

取自定義函數(shù)的定義

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期



這里可以看到,用到了用戶自定義的函數(shù),自定義的函數(shù)代碼如下:

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

這個函數(shù)實(shí)現(xiàn)的是 :

通過傳入一個機(jī)構(gòu)號,獲取 TAB_ANOTHER_XXX 表當(dāng)中的一級行的機(jī)構(gòu)號。


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

真相逐漸浮出水面

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期


到這里,小y腦子過了一次,基本上知道了問題的真相。讀者朋友們不妨思考一下,問題真相是什么呢?

 

別著急,多思考個三五分鐘,問題真相就在后面,什么時候往下翻,由你決定…

……

……

……

……

……

……

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

真相大白——成功反轉(zhuǎn)

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

到這里,小y終于想通了, 這不是壞塊,不是數(shù)據(jù)庫的一個BUG,恰恰想法,而是應(yīng)用程序的一個BUG!


當(dāng)應(yīng)用程序要執(zhí)行下列SQL時

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

需要注意的是 :

報錯 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ì)原因


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

為什么以前不出現(xiàn)??

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期


下屬某市級行原本屬于某省行(一級行),但是由于該市級行業(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)問題。


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

問題模擬重現(xiàn)

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期

原理解釋:

當(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ù)索引


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期


輸出結(jié)果如下所示 , 其中的 DATA_DEFAULT 字段就是函數(shù)索引的定義,對 trim/to_number/to_char 等自定義函數(shù)進(jìn)行排除后,就是自定義函數(shù)索引

這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(shù)人生系列第四十三期


2

然后使用下列命令來獲取函數(shù)定義


這個鍋,我們運(yùn)維,不背! 開發(fā)和運(yùn)維都該看看--技術(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ù)性。



向AI問一下細(xì)節(jié)

免責(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)容。

AI