在線重定義生產環境大表分區的慘烈踩雷記錄

尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️

加入LINE好友

本文來源於讀者投稿,作者在此分享在線重定義生產環境大表分區的慘烈踩雷記錄,感謝投稿,歡迎大家投稿分享自己日常中「難忘」的解決過程。

01

任務與方案

公司有一批大表需要分區,由於業務是24X7,所以停服是不可能的,只能考慮在線重定義。在線重定義推出已經很久了(不算新功能),但在生產上,還是沒用過,在測試環境進行模擬測試,很順利,速度也很快,幾千萬的表,十幾分鐘就完成了,於是方案就這樣敲定了;

02

開局

先從一張小表(1億記錄),按以下步驟:

第一步、空間準備、創建中間表(先分好區)、檢測是否可在線重定義;這個是準備工作;

第二步、啟動重定義(start_redef),這個會創建一些物化視圖等對象,然後插入當前記錄到中間表,這一步比較耗時間,如果開8個並行,一般150G的表15分鐘左右;

第三步、拷貝索引、約束、觸發器、統計信息等對象(copy_dep);這個也比較耗時,取決於表的大小與索引的多少,以150G的表,8個並行為例,索引約5分鐘一個,按10個索引算,這一步要50分鐘;

第四步、數據同步(sync_inter),原理是新的插入與更新都記錄在物化視圖中,然後同步到中間表去,如果不做這一步,切換時也會做這一個動作的;

第五步、把原表與中間表做一個調換(Finish_redef),這一步肯定會鎖表的,所以可以預見是有阻塞會話風險的,而且也未必一定能成功;

如果不成功或者中止了的話,就還有第六步:回退(Abort_redef),這一步目的是回滾到最初的狀態,這樣才會刪除物化視圖等中間對象,才可以重新進行重定義;

這些算是標準的步驟,但實際根據生產環境的情況(比如存在ogg復制),還需要做以下調整:

  1. 開始之前,最好是排除了中間表與物化表的復制,因為量太大,容易造成復制延時很長,寧可在目標環境也做一次重定義,如果能接受,也可以不排除;
  2. 在完成切換之後,要馬上重新加一下add trandata table_name,因為中間表切成了業務表,相當於是一個新表,不加的話,就會造成只有插入的記錄能復制,而更新的記錄的不能,時間隔得越久,需要修復的數據可能越多;
  3. 在數據同步之前,最好給中間表進行一次表分析,可以避免同步時走錯執行計劃;

按照以上步驟,前面幾個1億左右的小表都順利地完成了分區切換,開局還算不錯;

03

第一個雷:數據同步導致的鎖

完成了小表,便接著處理中等大小的表(1億-10億,50G-200G),開始時間都放在晚上22:00,但操作的時間明顯增長了,數據同步用時也很久,久就多等下唄,我也沒太在意,突然,手機簡訊報警,活動會話已達到50了,馬上登錄數據庫查,活動會話已是300多了,都是行鎖,而且阻塞源有多個,沒有發現明顯的根阻塞會話,為了盡快解除會話堆積問題,採取了kill全部阻塞源的方案,阻塞解決了,但也誤殺了一些業務會話;事後分析發現,真正的阻塞源還是數據同步引發的,數據同步是把物化視圖的數據merge到中間表,事實上的確是不阻塞業務表的,但一旦同步完成,sys用戶會立即啟動一個異步purgelog的任務,delete物化視圖日志的已同步數據,如果數據量一大,這個SQL就很慢(執行計劃不佳),它就會阻塞物化視圖日志的update,而物化視圖的update又會阻塞表的插入與update,造成了多層阻塞,如果層層追溯的話,還是可以找到根會話的,kill根會話即可;即便是吃過一次虧,後來我們也還是再上了一次當,出現了阻塞的情況但是仍然找不到阻塞源,原來這個purgelog的任務自動跑到另一個實例去運行了(RAC),而我們的檢測腳本卻是單實例的;

這一個雷的總結就是,數據同步也有阻塞的風險!原先一直以為,只有切換才會有鎖。

避開的辦法是,要麼找到業務最低谷時段進行操作,小表晚上22點就OK,但更大的表則不行,要到凌晨2:00才是最低谷;然後,不要想先提前把前面3步做完,等到低谷時來做同步與切換,因為間隔時間越長,物化日志量就越大,purgelog就越久; 總之,就是在低谷期做,而且是一氣呵成,要同步的量小,可能是最順利的;

這里,個人感覺oracle在這個地方完全可以加強一下,異步purgelog是否真的必要?能否允許設定不啟動?或者能否先不delete,搞完後一次性truncate?如果數據同步沒有阻塞問題,那就方便好多,把這些步驟分散進行,比如提前把多個表的初始化與索引弄好,並不斷同步,只在低谷期一一進行切換,效率就高得多;

04

第二個雷:進退停,都不行

在給某個表做切換時,到了數據同步這一步,發現數據同步沒法完成,眼看著造成越來越多的會話阻塞,只有停止它,

既然不能前進,那麼我們就回退,結果發現,回退也是久久不能完成,阻塞達到一定程度之後,只有中止回退,暫時停在這里,但停下來並不代表就沒有問題,物化視圖與日志在不斷增長,一天增長幾千萬,而且每次插入或更新都還要刷新物化視圖,高並發下造成了一次活動會話造過100的險情,感覺就像踩著了地雷,進也不能,退也不能,停在這里又有被敵人掃射的風險。

這下可紮心了,怎麼辦?請教同事朋友,以及相關的群,都沒這方面的經驗;開SR,從中文到英文,從二級到一級,也得不到有幫助的回答,oracle雖然文檔很多,但有些問題,也不容易找到答案。只有去分析它的行為,最終發現是一個遞歸SQL走錯了執行計劃(這個SQL也只是我的一篇文章《 記一次增加分區要兩個小時的優化案例 》里描述的那個SQL,,把這個SQL的執行計劃固化後,操作就正常了,完成了回退後,重新進行了一次重定義,分區完成;

對於這個坑,真的是很坑!而且還有可能不盡相同的入坑方式,一旦入了坑,可能面對的壓力會很大,因為可能好幾次變更都不能完成,進退兩難,最關鍵的是缺少可供參照的解決方案,只能具體問題,具體分析了;

05

第三個雷:執行計劃突變引發了宕機

中等大小的表做完後,還有一個62億記錄600GB的大表,這個表我最擔心的第一次同步數據時IO太大或時間太久,其實一些老數據是可以歸檔了,如果在線重定義能自定義初始化數據的範圍,比如只初始化最近三個月的數據,那就太好了,可惜不能,只能全量插入,但插入之後,我可以用truncate分區的方法把老數據清掉,這樣,後面建索引就快了,相當於同時做到了分區與歸檔的功能(老數據在原表以及ogg復制庫仍存在)。

這是特定場景的特殊用法,建立在兩個基礎以上:

  1. 在線重定義是通過物化視圖日志同步的,它通過merge的機制可以做到兩邊數據的一致性,但它並不強制要求兩邊一模一樣;只要物化視圖中insert與update能全部實施到中間表上,那麼最新的數據能保證是一致的,哪怕老數據已經沒有了;
  2. 我們的業務恰好是跟時間緊密相關的,3個月之前的數據已經很冷了,可以確認不會再有更新了。

最擔心的IO消耗竟然還比較好,開8個並行,共用了50分鐘,存儲的IO使用率沒有超過25%,之後清掉了老數據,建好索引,分析表,同步很快,切換很快,都順利地完成了,以後大石落定,開始處理OGG的事,這個時候,發現活動會話又上來了,仔細一看,竟然是一個相關的SQL走錯了執行計劃,由索引變成了分區全掃描!最悲催的是,這個時候,操作已不正常,無法像平時一樣,生成kill會話的SQL,記憶體在也沒有原來正確的執行計劃,想構造一個,任何操作一提交就變成了窗口「無響應」,接著,實例都連不上了,宕機了!馬上轉到另一個節點,有一些會話已經飄過來了,好在這個節點還可以正常操作,馬上構造正確的執行計劃,固化,然後KILL現有的全表掃描會話,情況得到了控制,再重啟掛了的節點,然後,只能是暗自阿彌佗佛,如果沒有控制住的話,那可能要跑路了;

其實執行計劃的變化,一開始就考慮過,所以每個表都要做一次統計,之前的表,就從來沒有出現過執行計劃的變化,但這個執行計劃的變化,跟表的分區有關,跟SQL的寫法不當也有關,總之就是沒有充分評估到這方面的風險,這方面是有欠缺的;

06

第四個雷:OGG的所有抽取都掛空擋了

進行各方面檢查後,看似一切正常了,但ogg的抽取任務卻有些怪,狀態是running的,但lag卻是不斷地增長,檢查目標端,數據沒有進來!納悶啊納悶,不只是這個表相關的extract,而是所有的extract都是這樣,可是又不報錯,反復STOP加START,還是一樣的情況,從來沒有遇到過這種現象,網上也找不到類似的案例,Strace也看起來是正常工作的,嘗試跳過大事務,沒有進展,嘗試跳過一點時間,也沒有解決,百思不得其解,陷入深深地困惑中……

時間一分一秒地過去,延時一分一秒地增長,也是一個耽誤不起的坑,於是決定拿一個表做測試,跳過較長的一段時間,發現報錯了,redo日志不可用(不在本地節點的問題),拷貝過來後,發現正常了!只能這麼幹,都往前跳一段時間,這個抽取正常了,開始追日志了,但代價是跳過的這一段時間,就需要去比對與手工同步了;

猜想這個跟600G的大表初始化生成了很多的日志文件有關,但具體怎麼相關,暫不清楚,惹不起,只能躲了。

07

寫在最後

終於走出了地雷陣,感覺是松了一口氣,盡管付出了慘痛的代價,但真的有很多值得吸取的經驗與教訓,如果我所付出的代價,能夠給到其他人一些參考,從而少踩一些坑,那也算值得了^_^

原創:ycc。

轉載:意向文章下方留言。