從一次數(shù)據(jù)遷移項目里,我得到的四個經(jīng)驗教訓(xùn)
不久前,我經(jīng)歷了一次數(shù)據(jù)遷移項目。前幾天,我跟一位架構(gòu)師探討了一下當(dāng)時的各個步驟,和我所選擇并進一步開發(fā)的解決方案。我覺得我應(yīng)該告訴他一些信息 ,避免他日后遷移數(shù)據(jù)時踩坑。
在我們的交流中 ,我提到了數(shù)據(jù)遷移的各種難題和我們遇到的問題?,F(xiàn)在我意識到,這些東西對許多從事數(shù)據(jù)遷移項目的人們來說都很有用。我聽說這些是很常見的問題,多是那些開始數(shù)字化轉(zhuǎn)型的公司容易遇到的 。數(shù)據(jù)遷移項目通常是一套解決方案,讓你提取、轉(zhuǎn)換舊數(shù)據(jù),然后將其存儲到新的系統(tǒng)中。
之前沒想到的是,我從事軟件工作以來只參與過一個數(shù)據(jù)遷移項目。感覺好像回到了我在學(xué)習(xí) SQL 時掙扎的日子。那時的經(jīng)歷很有意思,你在 Oracle 和 MariaDB 上都使用 PL/ SQL ,并為此頭痛不已。你只能自行猜測哪個是舊系統(tǒng),哪個是光芒萬丈的新系統(tǒng)。但今天不講這個,今天講我認(rèn)為導(dǎo)致延遲交付的最大陷阱。觀點是我自己的,但事情卻是大家都會遇到的,等等等等。
1. 用 SQL 腳本做主要工具
這是昨天早上我忘了向同事強調(diào)的一個問題,今天早上它又在我腦海閃現(xiàn)。別誤會,SQL 是強大的 數(shù)據(jù) 檢索和顯示工具。但是,當(dāng)你有一個由多個開發(fā)人員組成的團隊,并在同一個代碼庫上工作時,關(guān)鍵要確保你的更改能與其他代碼很好地整合。
問題在于,要驗證不同的場景 時 ,我們不能只花幾秒鐘或幾分鐘運行典型的單元測試。我們必須執(zhí)行實際的遷移,因此我不會稱之為“集成測試”,因為 集成測試的 環(huán)境與實際環(huán)境有所不同(后文會詳細(xì)介紹)。
我們必須啟動 docker 鏡像,然后給將來要 用真實數(shù)據(jù)應(yīng)對 的每種 場景 加載虛擬數(shù)據(jù)。我覺得我們的 Jenkins 構(gòu)建一次要 2-3 個小時才能完成。這使本地開發(fā)更加困難,因為沒有人愿意花 5 分鐘內(nèi)改代碼然后花 2-3 個小時來測試。最開始我們改為只運行我們需要的那些測試用例。那時 CI 慢 到, 我甚至在上一年專門發(fā)了一個帖子講這個事情 。最終,我們將時間降到了 40 分鐘,仍然很慢,但考慮到我們正在處理的內(nèi)容,可能這就是我們最好的選擇了。
https://www.codingnagger.com/2019/01/31/slow-ci/
現(xiàn)在我不是 在談我自己的經(jīng)驗 ,而是 在說 一些跟我討論過的架構(gòu)師 的看法 ,他們在那個項目 期間,甚至項目結(jié)束之后都向我建議 ,用一種實際的編程語言可以使我們免于這種痛苦:你可以 測試任意組件,完整的檢索 、轉(zhuǎn)換和加載 操作 只需幾秒鐘就夠了。然后你再對理想路徑進行一次集成測試。我們本來可以把 CI 構(gòu)建控制在一分鐘之內(nèi)的,從而節(jié)省很多時間。
2. 源字段和目標(biāo)字段對不上
字段不匹配是很痛的痛點。我不是指從源數(shù)據(jù)字段到目標(biāo)數(shù)據(jù)字段的對應(yīng)錯誤,而是指字段對應(yīng)沒問題,但目標(biāo)字段類型不對。由于數(shù)據(jù) 的 敏感 性 ,我們研究解決方案時接觸不到真實數(shù)據(jù)。
所以這種問題只有到了在生產(chǎn)環(huán)境運行時才會暴露出來。你可能會有一些源字段是字符串類型的,但目標(biāo)字段卻是整型的。當(dāng)所有測試數(shù)據(jù)都是數(shù)值時不會有問題,但當(dāng)在幾百萬實體中出現(xiàn)哪怕一兩條包含字母時,就全都完了。還有些時候數(shù)據(jù)會被截斷,因為目標(biāo)字段所能表達的值范圍比源字段要小。這種問題不是數(shù)據(jù)遷移工程的責(zé)任,因為目標(biāo)系統(tǒng)不是我們設(shè)計的,但實際上我們在交付數(shù)據(jù)遷移方案時卻不得不去修復(fù)這種問題。是的,現(xiàn)實并沒有那么理想。
所以在這里我要強調(diào)的是,如果你要構(gòu)建一個系統(tǒng)的新版本,請確保新的數(shù)據(jù)庫字段的類型和格式都能匹配源數(shù)據(jù)。我們不能截斷地址或電話號碼,尤其是當(dāng)我們系統(tǒng)需要這些信息時。
3. 與其他團隊邊界不明確
當(dāng)時,我的團隊是做數(shù)據(jù)遷移的。我們設(shè)計了一個解決方案,把數(shù)據(jù)從這里遷移到那里。但如上文所述,我們有時不得不修復(fù)目標(biāo)數(shù)據(jù)庫的問題,這些問題都是其他團隊為各種功能折騰出來的。最重要的是,我不明白我的團隊怎么就變成了其他團隊的測試數(shù)據(jù)提供者。反正 這些團隊不會把所有的測試數(shù)據(jù)匯總在一起以便測試其功能,而是會來找我們?yōu)樗麄兩呻S機的測試數(shù)據(jù)。
回想起來,這么做真蠢。因此,我們構(gòu)建的測試框架中有一個類用于生成數(shù)據(jù)。在 開發(fā)時,我們把這些數(shù)據(jù)存到源數(shù)據(jù)庫里,然后運行遷移過程,提取、轉(zhuǎn)換這些數(shù)據(jù),并把它們存到目標(biāo)數(shù)據(jù)庫里。接著再從目標(biāo)系統(tǒng)中導(dǎo)出這些數(shù)據(jù)發(fā)送給那些團隊。我們不得不這么做,因為我們不想在我們的職責(zé)范圍之外制造數(shù)據(jù)。但是,我認(rèn)為我們做的太多了。我們應(yīng)該把 底線控制 在“請您自行創(chuàng)建測試數(shù)據(jù)”上。
雖然幫助他人 也是可以的 ,但我們不能在自己本職工作都沒做完的情況下這么做。最后的結(jié)果就是,我們負(fù)責(zé)了整個工程的三個主要部分:數(shù)據(jù)遷移、修復(fù)目標(biāo)數(shù)據(jù)庫的問題、給每個人生成測試數(shù)據(jù)。
4. 不同環(huán)境的設(shè)置
我記得當(dāng)時我沒有過多考慮 各種部署 環(huán)境的不同設(shè)置。從開發(fā)環(huán)境到預(yù)發(fā)布環(huán)境,再到生產(chǎn)環(huán)境,它們 會 有很多差異。顯然,我們?yōu)榇烁冻隽舜鷥r。你可能會認(rèn)為不同版本間的 Oracle 數(shù)據(jù)庫或 MariaDB 數(shù)據(jù)庫應(yīng)該不會有什么大問題吧?但如果我告訴你下個版本跟這個版本的差異會破壞掉你所有的 SQL 腳本呢?就像必須把 VALUES 替換成 VALUE。
想象一下遷移工具在你本地運行得好好的,接下來你把它推送到一個緩慢的 CI 流程 。然后你再把它發(fā)布到一個環(huán)境,運行遷移過程并檢查 ,沒什么問題 。結(jié)果到生產(chǎn)環(huán)境出問題了,因為生產(chǎn)環(huán)境的 MariaDB 版本太老。此外,生產(chǎn)環(huán)境還是個 EC2 實例,而預(yù)發(fā)布環(huán)境則是 RDS。
這個項目在開發(fā)環(huán)境和在生產(chǎn)環(huán)境的變量設(shè)置完全一致,但我還是被它們輸出的差異驚到了。為 了 在不同集成環(huán)境里都能工作而到處改代碼 ,那些痛苦你都逃開了 。生產(chǎn)環(huán)境的配置 本應(yīng)能 證明你的解決方案可以在生產(chǎn)環(huán)境工作,但 其實 它跟真實的生產(chǎn)環(huán)境配置一點也不像, 這肯定就會出問題 。這絕對是我在這次經(jīng)歷中得到的最大一筆經(jīng)驗。
5. 總結(jié)
我將在余生中繼續(xù)學(xué)習(xí)從舊項目獲得的經(jīng)驗教訓(xùn)。我甚至?xí)販剡@篇博客文章來確保我不會忘記這些經(jīng)驗教訓(xùn),因為它們在我下次進行數(shù)據(jù)遷移時還是非常有用的。更妙的是,其中一些經(jīng)驗教訓(xùn)不僅僅可以用于數(shù)據(jù)遷移,還可以應(yīng)用于其他方面。
即使這次我沒有去找個工具來做, 本文談到 的 這些 經(jīng)驗也讓我堅信應(yīng)該找個好工具來做好工作。信任已有信息固然很好,但也不妨 去看看周圍 ,對自己也沒有什么壞處。有時這些工具并不比 SQL 查詢慢。
其次,盡可能確保開發(fā)環(huán)境的設(shè)置與生產(chǎn)環(huán)境匹配。這將避免許多集成問題。
最后,當(dāng)職責(zé)明確了之后,應(yīng)避免給自己攬更多的活兒,它們會妨礙你的本職工作。塞爾吉奧·拉莫斯(Sergio Ramos)并不是世界上最好的后衛(wèi),因為他本賽季得分超過菲爾米諾。最好的后衛(wèi)應(yīng)該是先做好自己擅長的防守工作,然后偶爾進進球。