天天看點

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

引言  

這個元旦不太平,剛剛發生了全球幾百套mongodb資料庫資料被人删除,讨要比特币做贖金的事件,這就又發生了一件詭異、罕見的事。

你也許從來沒想過,居然有一天,你的資料庫會建立不了對象,是因為42億個對象編号用到極限!而我居然真的遇到了!

故障現象  

是的,甭論是要建立全局臨時表,或者是序列,或者索引,都通通報錯!

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

是的,甭說是你,就是全球,也沒幾個人遇到過,看看mos文章就知道了:

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

唯一的一篇文章,告訴你遇到了一個bug,文章裡對這個bug的簡單描述是這樣:

如果你遇到ora-600 [kkdlron-max-objid]錯誤,說明建立對象的對象編号(object id)超過資料庫限制了!從mos文章和我們建立對象遇到的錯誤看,這個資料庫限制的最大對象編号是4254950911!這個bug在某些作業系統平台的某些版本上是有更新檔支援的,但是,但是,但是,重要的事情說三遍!這個所謂的更新檔,也隻不過是把這個資料庫限制的最大編号增大了一點兒而已,讓你好重建資料庫,然後在邏輯導入所有表,這些表會重新獲得新的對象編号。

那你肯定會關心,額滴神啊,我十幾個tb的資料,邏輯導入是一個小工程啊,要申請停機時間啊,這要老命了!

這麼個幺蛾子的情況,為什麼偏偏就被我遇到了呢?

是的,這種情況極為少見,但不是不會發生,墨菲定律大家都懂的,莫非,莫非,莫非就偏偏碰見了你!

有大量分區表或索引,對象會很頻繁drop然後又create的資料庫系統,就容易中招了!

故障分析  

首先來看看我們中招的資料庫,資料庫對象的最大編号是多少:

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

慢着!

報錯資訊說的啥?那個編号是4254950911,比目前資料庫系統中最大編号大460567, 難道是每個資料庫對象編号不是順序來的,而是中間要隔40多萬!

我們将資料庫最新建立的對象按時間倒序排列,可以看到相連兩個對象編号差别最大是1447773(wrh對象和sp對象),最小是1。這說明一個問題,對象建立時,編号還是順序連續來的。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

事實上,這個對象編号它就是一個資料庫“序列”。(題外話,你有沒有想過序列重置?思考下到底行還是不行?)

sql> select dataobj# from sys.obj$ where name='_next_object';

dataobj#

----------

4254950908

sql> select max(object_id),max(data_object_id) from dba_objects ;

max(object_id) max(data_object_id)

-------------- -------------------

4254909633 4254950794

從中我們可以看出,它申請的下一個序列值是4254950908,與建立對象報錯的值4254950911僅僅隻相差3而已。說明我們資料庫中目前還存在的最大對象編号之後,還是建立過幾十萬次對象的。

那接下來我們看看最近幾天建立的資料庫對象,每天的最大id是多大呢,也就是說資料庫編号每天增幅大概多少?

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

我們可以看到,最近10天,每天資料庫對象編号增長,最小是202萬,最大是459萬。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

這個資料庫是2013年建立的。

如果按照每日最大增幅算,4年時間最大的對象編号應該是:

4*365*4591144=6703070240

如果按照上圖顯示的最小增幅算,最大的對象編号應該是:

4*365*2028717=2961926820

而目前最大資料庫對象編号是4254490344,在這兩個數之間。也就是說,一句話,每天的資料庫對象編号增幅達百萬級。啥意思?每天有百萬次建立資料庫對象的指令?按每天最大增量算,平均每秒鐘要執行53次建立指令。

4591144/24/60/60=53.13824074

這顯然不太可能!

進一步研究看看,做一把日志挖掘?

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

考慮到資料日志産生量太大,沒有啟用歸檔模式。

是以,無法查詢到真實的ddl語句執行情況,也無從較真了。

但是,長遠來看,從應用層降低資料庫對象的drop/create頻率是必須的,從資料庫維護層監控對象編号也是必須的。

解決方案  

從短期來看,是否具有臨時解決方案(參數、或者更新檔,因為應用側到此已經徹底死掉了)可以繞過這個問題。

沒有參數,也沒有靈丹妙藥,但是看起來更新檔還不少:

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

不過,目前這個資料庫版本11.2.0.3支援的平台很少,隻有oracle自家的才被支援:

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

而故障資料庫的平台不在此列。也就是說,苟延殘喘的機會也破滅了!

撸起袖子幹吧!建新庫,邏輯導出,邏輯導入(impdp)!十幾個tb的資料要耗時多久呢?

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

原了解釋  

解釋一下,oracle支援的最大對象編号是多少?

下面這段内容來自偉翔同學:

“從oracle 8開始rowid改成由data_object_id#、 rfile#、 block# 、row#組成,它使用base64位編碼的18個字元顯示,其實rowid的存儲方式是:10 個位元組即80位存儲,其中資料對象編号需要32 位,相關檔案編号需要10 位,塊編号需要22,位行編号需要16 位,由此,我們可以得出,32位的對象編号,支援的最大編号為:”

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

報錯顯示的值是4254950911,與理論最大值相差4000萬,也就是說,如果打了更新檔,按照這個增速,也就是可以再蹦跶10天而已。

事後規避  

那怎麼辦呢?

我們對于危機的恐懼不在于到底有多艱難,而在于危機發生的不确定性。

是以,通過我們的苦難,寫這篇文章,給你們大家一個預警。

增加一個監控告警,最進階别,每天最大對象編号增長超過10萬,就告警。

做運維就是這樣,經驗和能力是通過一個又一個苦難堆積出來的。

資料庫運維哪家強?比拼的是團隊十年如一日的運維經驗總結積累。

運維靠的不是花裙秀腿,運維靠的是簡單實用,一招制敵!

介紹下幾個我們常用的資料庫配置、檢查的建議項,你一定用得着(每項都至少發生過一次生産上血淋淋的故障,但我們相信你可能隻做了一兩個):

oracle rac環境,禁用drm;

oracle rac環境,所有應用sequence緩存預設設定為500(特殊的可以更高,或者是0);

所有資料庫,audsess$這個sequence緩存設定為1000;

新應用上線,禁止使用db link;

所有新資料庫安裝,必須部署osw(rac庫開啟prvnet);

一個表空間最多不要超過1000個資料檔案;

……今天是不是應該增加一條應用每天新增的資料庫對象不超過10000個??這個資料庫總的資料庫對象也才20000個哦~

關于運維變更和監控的幾點規範:

關于涉及應用的變更(建立、删除、修改資料庫對象結構,新增sql語句),必須提前2天送出,sql稽核(可以通過人工,我們也做了自動的oracle sql稽核工具)通過後允許上線,否則必須經過一定級别上司的特批。

關于系統級的普通變更,不允許生産時間執行。

關于資料庫的監控,相信你可能已經設定了不少,每天都煩不勝煩了。但是以下這些,如果你還沒有部署,建議盡快實施:

scn天花闆監控

sequence最大值監控

……

以及我們今天學到的,對象最大編号增量監控

如果說大型系統的開發人員無法保證自己不編寫有bug的代碼,那麼專業的運維人員同樣無法保證自己不遇到故障(不要奇怪,比如hpux平台cp指令都是可能引發故障的,比如密集的ping指令也是,等等)。差别隻在于專業的運維團隊踩過足夠多的坑之後,可以幫助後來者規避掉這些坑而已,就像柯潔比聶衛平更年輕成為圍棋第一人這樣。至于master輕松戰勝柯潔,那是另一個玩法,很重要,也是運維人的新目标。

如果你還有補充,歡迎文末評論留言,讓還沒有master幫助的更多運維兄弟不走你走過的坑!

故障手工重制  

看到這裡,是不是覺得還是有點意猶未盡?我們也一樣,是以我們自己做了些測試。

基于12cr1的環境,我們直接把資料庫對象的最大編号修改了(聲明:我們隻是測試,不要在生産上幹!幹了出問題你自己負責!)。

指令:

update obj$ set dataobj#=4254950905where name='_next_object';

然後往資料庫裡面再建立幾個新表,立馬就故障重制了。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

相同的ora-600錯誤。

在這個版本,oracle是提供了更新檔的,趕緊下載下傳下來,打上去。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

再看看,是不是突破限制了。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

非常好, 至少是可以苟延殘喘了嘛!

我們再看看object_id最大可以到多少。

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

結論:不打更新檔隻能4254950910 ,打了更新檔可以到4293950910,這個是最大能到的object_id了,雖然你的資料庫可能永遠也用不到這個數。 

資料庫重建後的跟蹤分析  

比較幸運的是,發生故障的資料庫是一個與曆史資料關系不緊密的資料庫。是以很快在新的環境裡搭建了同版本的資料庫,導入對象邏輯結構後,業務就恢複了。

導入:

先做邏輯結構的導入;

再做資料的導入。

使用impdp+network方式,差不多每小時100gb的樣子。根據表類型分成不同的通道可以節省一些總時間。

新環境的object_id變化分析:

罕見故障!資料庫對象編号達到最大值,必須重建立庫!

我們可以看到,四天增長了接近18萬,平均每天4萬左右。

圖中沒有顯示得特别好的是,每天的data_object_id比object_id要快,但是新的object_id是基于max(data_object_id)的。

從這裡可以簡單看出,雖然新庫的object_id沒有像老庫臨死前幾天那樣每天幾百萬的增量,但每天幾萬仍然是一個不小的數字了。

這從另一個側面來說,頻繁truncate或drop/create 表是這類故障發起的誘因,盡管确實罕見。

關于神奇的4254950911  

這個神奇的數字,我們從mos文章id 76746.1:script: forbug:970640 to check if target database has been corrupted文章中找到一些資訊:

limit number:=2147483648; /* highest sensible object id */

maxobj number:=4294950911;/* max ever object id */

next_id number;              /* current next object_id*/

high_id number;             /*current highest object_id */

best_id number;             /*current highest object_id below limit */

badcnt number:=0;           /*number of objects with id above limit */

dups boolean:=false;        /*true if duplicate dataobj# */

*/

原文釋出時間為:2017-01-18

本文來自雲栖社群合作夥伴dbaplus