罕見故障!數據庫對象編號達到最大值,必須重新建庫!
引言
這個元旦不太平,剛剛發生了全球幾百套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
最後更新:2017-05-15 17:32:53