作者介紹
黎君原,新炬網路架構師,
“貳過”,重犯同一過失的意思,語出《論語》,完整句子為“不遷怒不貳過”,乃仲尼對其不幸早逝的弟子訊訓的極高評價,就it專案而言,從管理者的角度來說,一個錯誤犯兩次,別說是同一個人了,哪怕是同一團隊的不同人也不可接受,說到這里,不由得腦補出一位平時慈眉善目的老領導作嗔怒狀,大喊“干掉干掉”的恐怖場面,不重犯同一錯誤真的很難嗎,實話實說,確實難,君不聞,人類從歷史中得到的最大教訓就是從不吸取教訓,
筆者上述感嘆的背后是有故事的,那是本世紀最“2”的一天,筆者在排查Oracle到ADB(此處指ADB PG,全稱AnalyticDB PostgreSQL版,是阿里的MPP架構的資料庫)之間資料實時同步程序中,突然發現自己埋了個大雷——沒區分空值和空字串,導致同樣的欄位值在全量同步階段標志為空字串,增量同步階段則標志為空值,這顯然不是一種合乎邏輯的行為,
其實在發現這個問題前,筆者已經在這專案中苦苦掙扎了一個月,在此之前的兩天,筆者自以為資料質量已經完全沒問題,資料同步達到“又不是不能用”的境界了(筆者注:此處能用是真的能用,非為上線而上線那種能用),Oracle DB本身確實不區分空值和空字串,對于搞Oracle出身的工程師,沒意識到這個似乎情有可原,然而筆者作為搬磚佬,已經前前后后搬了十幾年,資料庫異構遷移專案也認認真真地做過好幾個,這件事對筆者而言,其實無異于“低級錯誤”,
回想起來,這個專案筆者做得甚是狼狽,這里面固然有進度緊以及新工具、新技術引入需要邊學邊用的客觀因素,但這不足以平息筆者對自己的憤怒,問題來了,在開源技術使用日益廣泛的今天,筆者也可能突然被要求用一個新工具同步資料到一個新資料庫,時間還可能更緊迫,到時怎么辦呢?再憤怒一次嗎?不了不了,還是腳踏實地總結一下,記下這些坑,日后類似專案,哪怕被拿著槍指著頭也好,下述問題都要在前期階段予以考慮,
一、空值和空字串
對于Oracle DB??,空值和空字串是同?回事,其中判斷某個值是否為空值/空字串統?使?"IS NULL"即可,?于=''是?效的,
這點對于其余資料庫來說,可真不?定了,就源端為Oracle DB,?標端為其余資料庫的項???,我們需要與開發商確認好,?標端究竟?哪種值表?源端的空值/空字符,?對于實時同步的項?來說,還需要在全量同步以及增量同步期間保持資料的?致,
除了空值和空字串以外,其實還有?個隱藏的?boss——固定?度型別中的空格值,以Oracle DB為例,char型別?于存放固定?度的字串,??度不?的字串則會被?動補充空格,對于這種值,?論是char_col=''還是char_col is null均?法識別,只能通過trim(char_col) is null識別,對此值使?length函式會回傳本欄位的?度,?個?0值,?這種資料同步到adb后則表現有?定差異了,char_col=''可以識別這種資料(哪怕ADB中也是?了固定?度的資料型別),然?對這個值使?char_length函式,結果會回傳0,如果實在要把這種資料抓出來,我們還得加?個條件oct_length(char_col)>0,很明顯,這?是?個坑!
二、資料型別轉換問題
筆者的朋友阿強一直立志做一個溫文儒雅的人,嗯,前提是不要讓他“寫材料”、“擦屁股”以及“估算作業量”!沒錯,“估算作業量”對他這種以txt狂魔自稱的人來說是一種煎熬,光說起這個詞,他已經腦補出把pm按在地上,一邊揍一邊說,“我想做個好人,為什么要逼我”?問題來了,如果讓阿強估算這個資料型別轉換的作業量,估計他連40米的刀都可以拿出來了,
跨資料庫的表欄位資料型別轉換作業主要涉及“精度”、“效率”、以及“兼容性”等方面,部分資料同步軟體確實具備自動轉換的功能,然而這種情況,僅對于管理規范的資料庫適用,不規范的庫則需要耗費較大精力了,下面舉幾個典型的例子說明這個問題:
- 以從Oracle DB到PG的同步為例,整型的值固然可以通過number型別(不設定精度和小數位)存放到源端Oracle資料庫中,問題來了,PG中應該用啥欄位對應了,僅僅安全起見,免得精度丟失,那肯定是numeric型別,然而這毫無疑問存在性能損失,Bigint等型別自然是更好的選擇,可是這又牽涉到與開發商溝通這樣有沒有可能導致應用報錯等情況了,這又是一個作業量,
- 以從Oracle DB到DB2的同步為例,DB2有一個隱性要求,組成主鍵的欄位值前后不能包含空格,否則會被過濾掉,這樣會造成一些在源端Oracle資料庫本來就不相同的兩條記錄的在目標端DB2庫被誤判為同一條記錄進而引發資料沖突,影響資料同步,
不要問為什么要在id類欄位加空格:第一,這是合法的;第二,這未嘗不是一種有創意的備份資料方法,這么干,真的,沒毛病!
- 以從Oracle DB到ADB的同步為例,由于MPP架構需要,我們需要額外指定DISTRIBUTED列,對于ADB而言,這里還有一個附帶的要求,這個列應當為主鍵的一部分,
- 以Oracle DB到HBase的同步為例,HBase是強制要求有主鍵的,否則不能同步,之前的專案中,筆者被迫無奈拿Oracle的轉換后的ROWID作為HBase的rowkey,滿足其同步前置條件,
為什么是轉換后?這又是另一個故事了,這里就不展開了,只提示個關鍵詞,“預磁區”,
嗯嗯,這明顯是個坑,那種由開發商定表結構的專案得心存感激,真的!
三、字符集轉換問題
字符集轉換深究起來其實并不是容易的事情,幾年前筆者所參與的一個O2O同步(即Oracle到Oracle的同步,下同) 遷移專案中,涉及了BIG5到UTF8的轉換,當時的同步工具為OGG,這個專案中各種亂七八糟的資料至今仍然對筆者歷歷在目,當然,這也讓筆者能更有經驗地處理異構資料庫同步中的字符集轉換問題,
跨字符集轉換的作業其實陷阱不少,因此,條件允許的話,筆者建議盡量規避,當然,遇到PG這種服務器端不支持GBK,而源端Oracle DB偏偏是GBK的情況,那只好迎難而上了,下面為筆者的建議:
- 涉及中文的情況,所見非所得,判斷一條中文記錄是否正常的依據,應該為其十六進制編碼是否正常,對于Oracle DB而言,我們可以用dump函式,其余DB需要找到類似的,
- 中文為多位元組字符,在不同的字符集下占用的位元組數并不一致,典型例子為GBK為2位元組,UTF8為3位元組,目標端環境可能需要相應調整位元組寬度,
- 不同字符集所涵蓋的漢字是不一樣的,例如BIG5中就沒有“邨”字,
- 字符集中有一個“自定義”區域,如不進行特殊處理,有可能導致資料丟失,
- “亂碼”會造成很大的困擾,對于Oracle DB而言,大致有如下幾種情況:
- 無法通過Oracle自帶convert函式轉換為目標庫編碼,以ADB為例,這部分資料會導致GPFDIST匯入失敗,進而影響資料全量同步,
- 可以通過Oracle自帶convert函式轉換為目標庫編碼,但無法重新轉換為原有資料,這部分資料會有潛在的資料丟失影響,對于遷移類專案需要重點關注是否涉及“自定義”字符區域,
- 含義不明的單位元組字符,如chr(0)、chr(255),這些字符往往夾雜在正常的字符中,以ADB為例,涉及dts( Data Transmission Service, 資料傳輸服務,系阿里的資料同步工具/服務)增量同步的話,相應記錄有資料一致性風險,
四、特殊字符處理
對于資料庫異構同步而言,特殊的字符,諸如單引號、雙引號、換行、斜杠、反斜杠等等也是一個困擾項,這一點在資料全量同步階段尤其明顯,
對于文本方式的全量資料同步來說,我們可以考慮下述幾種方式:
- 使用CSV格式;
- 使用多位元組分隔符;
- 進行資料清洗;
- 僅同步“正常”資料,“特殊”資料另行處理,
這些內容要說透,需要另外寫一篇文章了,
五、例外記錄處理
這里的例外記錄,指的是那種本身就違反資料庫規范,不應該插入到資料庫中的記錄,
以Oracle DB為例,筆者遇到的記錄有例外日期格式以及例外數值兩類,
- 例外日期格式,典型例子有"0000-00-00 00:00:00"和"2022-02-30 00:00:00",筆者在好幾個客戶環境都遇過這種資料,以至于筆者覺得這很“常見”,需要加到測驗專案里面,筆者這段時間做的Oracle到ADB同步專案確實遇到這種資料了,后者還造成dts的增量同步中斷,風險很高,所幸筆者的dts源端庫是基于OGG的目標庫部署的,Oracle自己的OGG工具也不能同步這種資料,這間接地擋了這部分例外的增量資料,在此基礎上,筆者只需要修復已有的例外資料即可,修復方法也很簡單,先+1再-1能修復大部分資料,至于不能修復的只能和業務協商重置一個值了,
- 例外數值型別,典型例子為NaN(即Not a Number),筆者僅在一個客戶環境中遇到,當時的場景為O2O同步 ,比較可怕的是連基本“來者不拒”的資料泵都無法同步這種資料,考慮到這個環境沒遇過這種資料,筆者這次偷懶了,沒做相應的測驗,
六、全量同步測驗
通常情況下,各種資料同步軟體都會自帶全量資料同步的功能,至于這個功能的效率、資源消耗、空間占用等專案需要進行評估,如果其不能滿足需求,則可能需要考慮替代的手段,
在選取測驗表的時候,筆者考慮綜合下面幾個因素選擇幾個測驗表:
- 需要包括大表,大表往往是個瓶頸項;
- 需要囊括本次同步涉及表的欄位型別;
- 如果環境中存在中文等多位元組資料,則建議包含這種表;
- 建議找靜態的表或者準靜態進行測驗,以方便核對資料一致性,
七、增量同步測驗
作為資料同步專案,同步效率是一個重要因素,筆者建議在搭建完整的同步鏈路之前,拿資料變更頻繁的關鍵表進行測驗,通過單表單行程的方式,剔除潛在的配置不當風險,
對于這方面,筆者建議如下:
- 盡量使用真實的資料;
筆者這次測驗通過Ogg同步增量資料,比較切合生產實際變更情況,這種方式可以參考,
- 增量同步發起后,在目標資料庫后臺觀察對應的SQL陳述句,以筆者本次專案為例,這個階段發現了兩個問題:
- 由于大小寫敏感問題,dts目標側未成功識別出主鍵,導致所有欄位被加到where條件,影響效率,此問題后來通過修改同步配置解決,
- 筆者觀察到dts側雖然設定了高并發度,但實際運行中,僅個別行程作業,其余處于空閑狀態,無法充分利用資源,此問題后來通過修改配置引數解決,
八、資料一致性測驗
資料一致性又是一個可以另外寫一篇文章的話題,對此,筆者建議如下:
- 對比靜態或者準靜態的資料,很顯然,筆者這次使用的ogg中間庫方案很切合這個主題,如果沒這個,筆者只能通過停止同步行程后反查其停在哪個點,再用這個時間點做檢驗了,這個想法理論上可行,然而以筆者對dts的淺薄理解,這條路并不通,原因在于dts所停的時間點并不完全準確,
- 活用md5函式,大部分正經的資料庫均包含內置的md5函式(PS:無意內涵DB2,真不是故意的),這可以將一個復雜的字串簡化,以便用于運算確認兩端的資料一致性,
九、軟體局限性
“越是漂亮的女人就越會騙人,記住啊!”
“不光是漂亮的女人不能相信,連貌似忠良的男人也不能相信,”
我覺得這段對話充分展示了一個產品的售前與售后的結局——殊途同歸,對于售前來說,拼指標、造場景、講故事等等手段都是為了證明我家產品很棒,快來買買買;就售后而言,找到產品的痛點,予以規避,以達到保證作業順利開展,避免一口大鍋從天而降的目的,大家都是靠博弈而生的,沒什么兩樣,手里的牌均是對技術的了解,
扯遠了,回到it專案中,異構資料庫的同步往往是邏輯的同步方式,這種方式必然有各種瓶頸的,對售后來說,再怎么謾罵售前“管殺不管埋”也無濟于事,最現實的做法莫過于:找到短板,通過改善流程、優化需求甚至協同開發商改造應用的方式保證軟體的穩定運行,
這里先講個故事,Timesten是Oracle的記憶體資料庫,其Cachegroup功能可以實作從物理庫(即Oracle DB)到記憶體庫的實時資料同步,而這個同步延遲對業務穩定運行是非常關鍵的,在實際使用中,運維人員總結出的經驗就是得規避大事務變更,最終他們與開發商達成相應的操作規范,無論是業務變更需求也好,資料庫運維發起的清理作業也罷,如涉及Timestens同步的表,都得遵循變更量達10w萬就得分批提交,每個批次2萬條記錄,每批次之間sleep 30秒的硬性規定,我覺得這個故事的結局很完滿了,真的,要是換成非得揪著Timesten不放,意圖純粹靠軟體解決問題的話,那才是妥妥的災難現場呢,畢竟其基于trigger的同步機制從原理上就對大事務極不友好……
問題來了,如何找到軟體的短板呢?
閱讀官方檔案自然是一個渠道,當然,閱讀也是有“技巧” 的 :
- 我們支持xx指標以內的場景,這句話可以理解為超過這個您就得想想辦法了,同時,這個值也許是要打個折的,畢竟環境不一樣,存在差異也是很合理的,
- 我們支持功能a,也支持功能b,這都是實話,至于同時支持功能a和b是您自己認為的,我可沒說,
這個嘛,春秋筆法是有的,這種玩法自古就有了,陳壽不也沒在《三國志》里面明說司馬昭弒君嗎,后來大家不都知道了嗎?
除了檔案以外,我們還可以考慮結合自身經驗考慮下述點,
- 大事務測驗
分別對同步范圍內外的物件做批量操作,加大資料庫日志量,觀察其對資料同步以及系統的影響,具體包括cpu、記憶體、io、空間等資源消耗以及同步延遲等,
以dts為例,源端oracle資料庫產生的所有資料均會被拉到dts的庫中分析,哪怕這資料與我們的同步策略無關,
目前有個黑名單功能可以繞過這問題,
- 長事務測驗
包含啟動增量同步前開啟的事務能否正常同步、長時間未提交的事務是否影響同步行程重啟等維度,
很明顯, 這是被ogg嚇到的結果,
- 頻繁事務測驗
筆者曾在O2O同步環境中遇到某應用使用了大量with as語法,后者隱式開啟了大量的短事務,進而短時間內事務量暴漲,進而 導致同步軟體Ogg抽取行程出現延遲,這個問題后來找開發商修改陳述句就解決了,然而其對筆者的心理陰影一直都在,以至于每遇到一個新場景,均會想想會不會遇到類似的問題,
- 事務順序
這個探究的是,軟體同步是否能保持事務的順序,如不能保持,那就得多留個心眼了,這種情況輕則導致同步延遲誤判,重則導致舊 資料覆寫新資料,影響資料一致性,
一個簡單的測驗樣例為,創建一個周期性(如每分鐘)更新的時間戳表,這個表的記錄數與源端Oracle DB的節點數一致,定時腳本依次連接各個實體并以當前時間更新相應的欄位,在目標端,我們可以通過查詢時間點表觀察會不會出現下面兩種情況:
- 后更新的資料是否會先被查詢出來;
- 同步出現延遲的話,時間戳表記錄的時間會不會與同步行程的時間戳保持一致,
- 批量ddl測驗
對于基于資料庫日志的同步工具,大批量的DDL陳述句很可能會觸發源端決議緩慢的情況,畢竟這涉及與資料字典的互動,
筆者曾遇過某個基于Ogg的O2O同步環境遇到這種瓶頸,而最終的解決方案為調整開發商版本上載的腳本,加大DDL陳述句之間等待時間間隔,
- 基于同步原理短板的探究
對于基于rowid的同步方案,沒啥好說的,只能從規范上減少move、shrink等改變rowid操作,實在要操作的話,需要重新同步相應的資料,
對于基于主鍵的同步方案,則重點考慮如何處理無主鍵表如何處理,
- 行程重啟測驗
包含兩種場景,正常重啟以及例外重啟,
例外重啟即高可用方面的,具體不展開了;至于正常重啟的話,需要觀察行程的一些自定義引數會不會被重置,
作者介紹
黎君原,新炬網路架構師,
“貳過”,重犯同一過失的意思,語出《論語》,完整句子為“不遷怒不貳過”,乃仲尼對其不幸早逝的弟子訊訓的極高評價,就it專案而言,從管理者的角度來說,一個錯誤犯兩次,別說是同一個人了,哪怕是同一團隊的不同人也不可接受,說到這里,不由得腦補出一位平時慈眉善目的老領導作嗔怒狀,大喊“干掉干掉”的恐怖場面,不重犯同一錯誤真的很難嗎,實話實說,確實難,君不聞,人類從歷史中得到的最大教訓就是從不吸取教訓,
筆者上述感嘆的背后是有故事的,那是本世紀最“2”的一天,筆者在排查Oracle到ADB(此處指ADB PG,全稱AnalyticDB PostgreSQL版,是阿里的MPP架構的資料庫)之間資料實時同步程序中,突然發現自己埋了個大雷——沒區分空值和空字串,導致同樣的欄位值在全量同步階段標志為空字串,增量同步階段則標志為空值,這顯然不是一種合乎邏輯的行為,
其實在發現這個問題前,筆者已經在這專案中苦苦掙扎了一個月,在此之前的兩天,筆者自以為資料質量已經完全沒問題,資料同步達到“又不是不能用”的境界了(筆者注:此處能用是真的能用,非為上線而上線那種能用),Oracle DB本身確實不區分空值和空字串,對于搞Oracle出身的工程師,沒意識到這個似乎情有可原,然而筆者作為搬磚佬,已經前前后后搬了十幾年,資料庫異構遷移專案也認認真真地做過好幾個,這件事對筆者而言,其實無異于“低級錯誤”,
回想起來,這個專案筆者做得甚是狼狽,這里面固然有進度緊以及新工具、新技術引入需要邊學邊用的客觀因素,但這不足以平息筆者對自己的憤怒,問題來了,在開源技術使用日益廣泛的今天,筆者也可能突然被要求用一個新工具同步資料到一個新資料庫,時間還可能更緊迫,到時怎么辦呢?再憤怒一次嗎?不了不了,還是腳踏實地總結一下,記下這些坑,日后類似專案,哪怕被拿著槍指著頭也好,下述問題都要在前期階段予以考慮,
一、空值和空字串
對于Oracle DB??,空值和空字串是同?回事,其中判斷某個值是否為空值/空字串統?使?"IS NULL"即可,?于=''是?效的,
這點對于其余資料庫來說,可真不?定了,就源端為Oracle DB,?標端為其余資料庫的項???,我們需要與開發商確認好,?標端究竟?哪種值表?源端的空值/空字符,?對于實時同步的項?來說,還需要在全量同步以及增量同步期間保持資料的?致,
除了空值和空字串以外,其實還有?個隱藏的?boss——固定?度型別中的空格值,以Oracle DB為例,char型別?于存放固定?度的字串,??度不?的字串則會被?動補充空格,對于這種值,?論是char_col=''還是char_col is null均?法識別,只能通過trim(char_col) is null識別,對此值使?length函式會回傳本欄位的?度,?個?0值,?這種資料同步到adb后則表現有?定差異了,char_col=''可以識別這種資料(哪怕ADB中也是?了固定?度的資料型別),然?對這個值使?char_length函式,結果會回傳0,如果實在要把這種資料抓出來,我們還得加?個條件oct_length(char_col)>0,很明顯,這?是?個坑!
二、資料型別轉換問題
筆者的朋友阿強一直立志做一個溫文儒雅的人,嗯,前提是不要讓他“寫材料”、“擦屁股”以及“估算作業量”!沒錯,“估算作業量”對他這種以txt狂魔自稱的人來說是一種煎熬,光說起這個詞,他已經腦補出把pm按在地上,一邊揍一邊說,“我想做個好人,為什么要逼我”?問題來了,如果讓阿強估算這個資料型別轉換的作業量,估計他連40米的刀都可以拿出來了,
跨資料庫的表欄位資料型別轉換作業主要涉及“精度”、“效率”、以及“兼容性”等方面,部分資料同步軟體確實具備自動轉換的功能,然而這種情況,僅對于管理規范的資料庫適用,不規范的庫則需要耗費較大精力了,下面舉幾個典型的例子說明這個問題:
- 以從Oracle DB到PG的同步為例,整型的值固然可以通過number型別(不設定精度和小數位)存放到源端Oracle資料庫中,問題來了,PG中應該用啥欄位對應了,僅僅安全起見,免得精度丟失,那肯定是numeric型別,然而這毫無疑問存在性能損失,Bigint等型別自然是更好的選擇,可是這又牽涉到與開發商溝通這樣有沒有可能導致應用報錯等情況了,這又是一個作業量,
- 以從Oracle DB到DB2的同步為例,DB2有一個隱性要求,組成主鍵的欄位值前后不能包含空格,否則會被過濾掉,這樣會造成一些在源端Oracle資料庫本來就不相同的兩條記錄的在目標端DB2庫被誤判為同一條記錄進而引發資料沖突,影響資料同步,
不要問為什么要在id類欄位加空格:第一,這是合法的;第二,這未嘗不是一種有創意的備份資料方法,這么干,真的,沒毛病!
- 以從Oracle DB到ADB的同步為例,由于MPP架構需要,我們需要額外指定DISTRIBUTED列,對于ADB而言,這里還有一個附帶的要求,這個列應當為主鍵的一部分,
- 以Oracle DB到HBase的同步為例,HBase是強制要求有主鍵的,否則不能同步,之前的專案中,筆者被迫無奈拿Oracle的轉換后的ROWID作為HBase的rowkey,滿足其同步前置條件,
為什么是轉換后?這又是另一個故事了,這里就不展開了,只提示個關鍵詞,“預磁區”,
嗯嗯,這明顯是個坑,那種由開發商定表結構的專案得心存感激,真的!
三、字符集轉換問題
字符集轉換深究起來其實并不是容易的事情,幾年前筆者所參與的一個O2O同步(即Oracle到Oracle的同步,下同) 遷移專案中,涉及了BIG5到UTF8的轉換,當時的同步工具為OGG,這個專案中各種亂七八糟的資料至今仍然對筆者歷歷在目,當然,這也讓筆者能更有經驗地處理異構資料庫同步中的字符集轉換問題,
跨字符集轉換的作業其實陷阱不少,因此,條件允許的話,筆者建議盡量規避,當然,遇到PG這種服務器端不支持GBK,而源端Oracle DB偏偏是GBK的情況,那只好迎難而上了,下面為筆者的建議:
- 涉及中文的情況,所見非所得,判斷一條中文記錄是否正常的依據,應該為其十六進制編碼是否正常,對于Oracle DB而言,我們可以用dump函式,其余DB需要找到類似的,
- 中文為多位元組字符,在不同的字符集下占用的位元組數并不一致,典型例子為GBK為2位元組,UTF8為3位元組,目標端環境可能需要相應調整位元組寬度,
- 不同字符集所涵蓋的漢字是不一樣的,例如BIG5中就沒有“邨”字,
- 字符集中有一個“自定義”區域,如不進行特殊處理,有可能導致資料丟失,
- “亂碼”會造成很大的困擾,對于Oracle DB而言,大致有如下幾種情況:
- 無法通過Oracle自帶convert函式轉換為目標庫編碼,以ADB為例,這部分資料會導致GPFDIST匯入失敗,進而影響資料全量同步,
- 可以通過Oracle自帶convert函式轉換為目標庫編碼,但無法重新轉換為原有資料,這部分資料會有潛在的資料丟失影響,對于遷移類專案需要重點關注是否涉及“自定義”字符區域,
- 含義不明的單位元組字符,如chr(0)、chr(255),這些字符往往夾雜在正常的字符中,以ADB為例,涉及dts( Data Transmission Service, 資料傳輸服務,系阿里的資料同步工具/服務)增量同步的話,相應記錄有資料一致性風險,
四、特殊字符處理
對于資料庫異構同步而言,特殊的字符,諸如單引號、雙引號、換行、斜杠、反斜杠等等也是一個困擾項,這一點在資料全量同步階段尤其明顯,
對于文本方式的全量資料同步來說,我們可以考慮下述幾種方式:
- 使用CSV格式;
- 使用多位元組分隔符;
- 進行資料清洗;
- 僅同步“正常”資料,“特殊”資料另行處理,
這些內容要說透,需要另外寫一篇文章了,
五、例外記錄處理
這里的例外記錄,指的是那種本身就違反資料庫規范,不應該插入到資料庫中的記錄,
以Oracle DB為例,筆者遇到的記錄有例外日期格式以及例外數值兩類,
- 例外日期格式,典型例子有"0000-00-00 00:00:00"和"2022-02-30 00:00:00",筆者在好幾個客戶環境都遇過這種資料,以至于筆者覺得這很“常見”,需要加到測驗專案里面,筆者這段時間做的Oracle到ADB同步專案確實遇到這種資料了,后者還造成dts的增量同步中斷,風險很高,所幸筆者的dts源端庫是基于OGG的目標庫部署的,Oracle自己的OGG工具也不能同步這種資料,這間接地擋了這部分例外的增量資料,在此基礎上,筆者只需要修復已有的例外資料即可,修復方法也很簡單,先+1再-1能修復大部分資料,至于不能修復的只能和業務協商重置一個值了,
- 例外數值型別,典型例子為NaN(即Not a Number),筆者僅在一個客戶環境中遇到,當時的場景為O2O同步 ,比較可怕的是連基本“來者不拒”的資料泵都無法同步這種資料,考慮到這個環境沒遇過這種資料,筆者這次偷懶了,沒做相應的測驗,
六、全量同步測驗
通常情況下,各種資料同步軟體都會自帶全量資料同步的功能,至于這個功能的效率、資源消耗、空間占用等專案需要進行評估,如果其不能滿足需求,則可能需要考慮替代的手段,
在選取測驗表的時候,筆者考慮綜合下面幾個因素選擇幾個測驗表:
- 需要包括大表,大表往往是個瓶頸項;
- 需要囊括本次同步涉及表的欄位型別;
- 如果環境中存在中文等多位元組資料,則建議包含這種表;
- 建議找靜態的表或者準靜態進行測驗,以方便核對資料一致性,
七、增量同步測驗
作為資料同步專案,同步效率是一個重要因素,筆者建議在搭建完整的同步鏈路之前,拿資料變更頻繁的關鍵表進行測驗,通過單表單行程的方式,剔除潛在的配置不當風險,
對于這方面,筆者建議如下:
- 盡量使用真實的資料;
筆者這次測驗通過Ogg同步增量資料,比較切合生產實際變更情況,這種方式可以參考,
- 增量同步發起后,在目標資料庫后臺觀察對應的SQL陳述句,以筆者本次專案為例,這個階段發現了兩個問題:
- 由于大小寫敏感問題,dts目標側未成功識別出主鍵,導致所有欄位被加到where條件,影響效率,此問題后來通過修改同步配置解決,
- 筆者觀察到dts側雖然設定了高并發度,但實際運行中,僅個別行程作業,其余處于空閑狀態,無法充分利用資源,此問題后來通過修改配置引數解決,
八、資料一致性測驗
資料一致性又是一個可以另外寫一篇文章的話題,對此,筆者建議如下:
- 對比靜態或者準靜態的資料,很顯然,筆者這次使用的ogg中間庫方案很切合這個主題,如果沒這個,筆者只能通過停止同步行程后反查其停在哪個點,再用這個時間點做檢驗了,這個想法理論上可行,然而以筆者對dts的淺薄理解,這條路并不通,原因在于dts所停的時間點并不完全準確,
- 活用md5函式,大部分正經的資料庫均包含內置的md5函式(PS:無意內涵DB2,真不是故意的),這可以將一個復雜的字串簡化,以便用于運算確認兩端的資料一致性,
九、軟體局限性
“越是漂亮的女人就越會騙人,記住啊!”
“不光是漂亮的女人不能相信,連貌似忠良的男人也不能相信,”
我覺得這段對話充分展示了一個產品的售前與售后的結局——殊途同歸,對于售前來說,拼指標、造場景、講故事等等手段都是為了證明我家產品很棒,快來買買買;就售后而言,找到產品的痛點,予以規避,以達到保證作業順利開展,避免一口大鍋從天而降的目的,大家都是靠博弈而生的,沒什么兩樣,手里的牌均是對技術的了解,
扯遠了,回到it專案中,異構資料庫的同步往往是邏輯的同步方式,這種方式必然有各種瓶頸的,對售后來說,再怎么謾罵售前“管殺不管埋”也無濟于事,最現實的做法莫過于:找到短板,通過改善流程、優化需求甚至協同開發商改造應用的方式保證軟體的穩定運行,
這里先講個故事,Timesten是Oracle的記憶體資料庫,其Cachegroup功能可以實作從物理庫(即Oracle DB)到記憶體庫的實時資料同步,而這個同步延遲對業務穩定運行是非常關鍵的,在實際使用中,運維人員總結出的經驗就是得規避大事務變更,最終他們與開發商達成相應的操作規范,無論是業務變更需求也好,資料庫運維發起的清理作業也罷,如涉及Timestens同步的表,都得遵循變更量達10w萬就得分批提交,每個批次2萬條記錄,每批次之間sleep 30秒的硬性規定,我覺得這個故事的結局很完滿了,真的,要是換成非得揪著Timesten不放,意圖純粹靠軟體解決問題的話,那才是妥妥的災難現場呢,畢竟其基于trigger的同步機制從原理上就對大事務極不友好……
問題來了,如何找到軟體的短板呢?
閱讀官方檔案自然是一個渠道,當然,閱讀也是有“技巧” 的 :
- 我們支持xx指標以內的場景,這句話可以理解為超過這個您就得想想辦法了,同時,這個值也許是要打個折的,畢竟環境不一樣,存在差異也是很合理的,
- 我們支持功能a,也支持功能b,這都是實話,至于同時支持功能a和b是您自己認為的,我可沒說,
這個嘛,春秋筆法是有的,這種玩法自古就有了,陳壽不也沒在《三國志》里面明說司馬昭弒君嗎,后來大家不都知道了嗎?
除了檔案以外,我們還可以考慮結合自身經驗考慮下述點,
- 大事務測驗
分別對同步范圍內外的物件做批量操作,加大資料庫日志量,觀察其對資料同步以及系統的影響,具體包括cpu、記憶體、io、空間等資源消耗以及同步延遲等,
以dts為例,源端oracle資料庫產生的所有資料均會被拉到dts的庫中分析,哪怕這資料與我們的同步策略無關,
目前有個黑名單功能可以繞過這問題,
- 長事務測驗
包含啟動增量同步前開啟的事務能否正常同步、長時間未提交的事務是否影響同步行程重啟等維度,
很明顯, 這是被ogg嚇到的結果,
- 頻繁事務測驗
筆者曾在O2O同步環境中遇到某應用使用了大量with as語法,后者隱式開啟了大量的短事務,進而短時間內事務量暴漲,進而 導致同步軟體Ogg抽取行程出現延遲,這個問題后來找開發商修改陳述句就解決了,然而其對筆者的心理陰影一直都在,以至于每遇到一個新場景,均會想想會不會遇到類似的問題,
- 事務順序
這個探究的是,軟體同步是否能保持事務的順序,如不能保持,那就得多留個心眼了,這種情況輕則導致同步延遲誤判,重則導致舊 資料覆寫新資料,影響資料一致性,
一個簡單的測驗樣例為,創建一個周期性(如每分鐘)更新的時間戳表,這個表的記錄數與源端Oracle DB的節點數一致,定時腳本依次連接各個實體并以當前時間更新相應的欄位,在目標端,我們可以通過查詢時間點表觀察會不會出現下面兩種情況:
- 后更新的資料是否會先被查詢出來;
- 同步出現延遲的話,時間戳表記錄的時間會不會與同步行程的時間戳保持一致,
- 批量ddl測驗
對于基于資料庫日志的同步工具,大批量的DDL陳述句很可能會觸發源端決議緩慢的情況,畢竟這涉及與資料字典的互動,
筆者曾遇過某個基于Ogg的O2O同步環境遇到這種瓶頸,而最終的解決方案為調整開發商版本上載的腳本,加大DDL陳述句之間等待時間間隔,
- 基于同步原理短板的探究
對于基于rowid的同步方案,沒啥好說的,只能從規范上減少move、shrink等改變rowid操作,實在要操作的話,需要重新同步相應的資料,
對于基于主鍵的同步方案,則重點考慮如何處理無主鍵表如何處理,
- 行程重啟測驗
包含兩種場景,正常重啟以及例外重啟,
例外重啟即高可用方面的,具體不展開了;至于正常重啟的話,需要觀察行程的一些自定義引數會不會被重置,
本文來自博客園,作者:古道輕風,轉載請注明原文鏈接:https://www.cnblogs.com/88223100/p/9_big_pits_buried_by_heterogeneous_database_migration.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/445401.html
標籤:其他
上一篇:MySQL優化之索引決議
