1、數(shù)據(jù)遷移的原因
在業(yè)務(wù)發(fā)展過程中痢艺,有很多的原因會導致我們需要進行數(shù)據(jù)遷移:
- 機器的性能或容量問題需要更換機器
- 原有的分表設(shè)計跟不上業(yè)務(wù)發(fā)展導致單表性能出現(xiàn)瓶頸
- 原有的數(shù)據(jù)庫選型無法適應(yīng)業(yè)務(wù)的發(fā)展導致數(shù)據(jù)庫存在性能問題
- 原有的數(shù)據(jù)結(jié)構(gòu)設(shè)計無法滿足新的業(yè)務(wù)場景
- ……
上述原因?qū)е碌臄?shù)據(jù)遷移中,有些只需要將原數(shù)據(jù)原封不動地騰挪到新的機器餐蔬;有些雖然保持數(shù)據(jù)結(jié)構(gòu)不變俐芯,但需要更換數(shù)據(jù)庫,或者更換數(shù)據(jù)的路由方式后雷;如果還牽涉到數(shù)據(jù)結(jié)構(gòu)的變更,則數(shù)據(jù)遷移會變得更加地麻煩阶牍。
2喷面、數(shù)據(jù)遷移的目標
做數(shù)據(jù)遷移工作,首要面對的目標當然是數(shù)據(jù)不能丟走孽,但也不止這個惧辈,隨業(yè)務(wù)的特點不同,要考慮:
- 數(shù)據(jù)允不允許有記錄丟失
- 數(shù)據(jù)允不允許有字段內(nèi)容的缺失
- 數(shù)據(jù)允不允許有記錄重復
- 數(shù)據(jù)能不能只讀不寫
- 系統(tǒng)允不允許停止提供服務(wù)
- 系統(tǒng)有沒有訪問量特別少甚至為0的時間段
- 遷移的時長能不能持續(xù)一段較長的時間
- ……
以上的考量點磕瓷,答案為否的條數(shù)越多盒齿,則遷移的難度越大。
3困食、數(shù)據(jù)遷移的基本策略
隨著人們不斷地執(zhí)行一次次的數(shù)據(jù)遷移边翁,已經(jīng)得出了幾套基本的遷移策略,來供不同的業(yè)務(wù)訴求場景下去使用硕盹。常見的遷移策略有:
- 停機切換
- 在線切換-增量寫新
- 在線切換-雙寫
3.1符匾、停機切換
對于第一種停機切換來說,操作步驟是最簡單的瘩例,分為三步:
- 停機掛公告
- 遷移數(shù)據(jù)
- 恢復服務(wù)
為什么說它簡單啊胶,是因為這種做法只涉及停機前的存量數(shù)據(jù)的遷移,數(shù)據(jù)沒有因為系統(tǒng)的運行而持續(xù)變化垛贤,因此只需要將固定的存量數(shù)據(jù)復制到新庫即可焰坪,即使是要更換存儲方式或數(shù)據(jù)結(jié)構(gòu),也是一個一次性的工作聘惦。
這同樣是最穩(wěn)妥的方式某饰,由于系統(tǒng)暫停了服務(wù),不會再有新數(shù)據(jù)的產(chǎn)生善绎,因此只需要仔細處理好固定的一份存量數(shù)據(jù)的遷移黔漂,做好對賬檢查確認無誤,即可恢復服務(wù)完成遷移禀酱。
相對應(yīng)的炬守,就是這種方式對業(yè)務(wù)的巨大限制——停機。
大部分對外提供服務(wù)的業(yè)務(wù)比勉,都不會希望自己需要為了一個技術(shù)上的問題,去暫停重要的服務(wù)能力。
但我認為其實很多時候這個看似無法被接受的限制是可以探討的:熱門游戲如王者榮耀浩聋,也會偶爾有停服維護的時候观蜗;民生服務(wù)如12306,也在每天凌晨不提供購票能力衣洁。
歸根結(jié)底墓捻,這是一個業(yè)務(wù)可用性與技術(shù)優(yōu)化上的權(quán)衡,作為研發(fā)人員坊夫,需要清晰地讓業(yè)務(wù)同學理解數(shù)據(jù)遷移的重要性和好處砖第,以及方案選型的考量,供業(yè)務(wù)同學去理解其意義环凿,才能做出權(quán)衡與選擇梧兼。
如果是非常關(guān)鍵的業(yè)務(wù),比如作為移動支付渠道卻無法支付智听,或者作為電商卻無法提交訂單羽杰,無疑會對業(yè)務(wù)帶來巨大損失,這也是為什么這種業(yè)務(wù)從來不曾停機維護到推,甚至一旦不可用就會上熱搜考赛。
但作為非關(guān)鍵流程的業(yè)務(wù),如果能找到一個訪問量非常低的時間段(如凌晨)莉测,提前掛出通知做好對用戶的周知颜骤,在盡量短的時間完成數(shù)據(jù)遷移并恢復服務(wù),是可以被業(yè)務(wù)所接受的捣卤,也能大大降低數(shù)據(jù)遷移的復雜度和風險忍抽。
3.2、在線切換
如果業(yè)務(wù)實在無法接受暫停提供服務(wù)腌零,那就只能在線切換梯找。
在線切換是指服務(wù)不停機的情況下,通過同時提供新舊兩套數(shù)據(jù)的訪問能力益涧,并按某種規(guī)則將來自用戶的請求從舊的數(shù)據(jù)切換到新數(shù)據(jù)的過程锈锤。
在這個過程中,不可避免的闲询,會有部分用戶訪問到新數(shù)據(jù)久免,部分用戶訪問到舊數(shù)據(jù),最好能做到用戶無感知扭弧。
如果在切換的過程中阎姥,發(fā)現(xiàn)有問題,還要能夠方便地回退回舊數(shù)據(jù)鸽捻,回退后同樣希望保障數(shù)據(jù)是一致的呼巴。
3.2.1泽腮、在線切換-增量寫新
對數(shù)據(jù)的切換,必然有一個存量數(shù)據(jù)的遷移過程衣赶,但和停機切換不同诊赊,在存量數(shù)據(jù)的遷移過程中,數(shù)據(jù)是持續(xù)在產(chǎn)生的府瞄,因此就像阿基米德的龜兔賽跑悖論碧磅,你永遠也無法保障在完成存量數(shù)據(jù)遷移的那一刻,和切換使用新數(shù)據(jù)的那一刻之間遵馆,沒有新數(shù)據(jù)產(chǎn)生鲸郊,何況這兩個時刻的間隔往往比我們想象的時間更長。
因此你需要有一個將新增的數(shù)據(jù)寫入新的數(shù)據(jù)庫的過程货邓。這就是增量寫新秆撮。
由此整個邏輯基本確定了:
- 讀請求雙讀新舊并組裝數(shù)據(jù)
- 則良辰吉日開始,所有的新的數(shù)據(jù)寫請求都訪問新數(shù)據(jù)庫
- 遷移存量數(shù)據(jù)到新數(shù)據(jù)庫
- 將讀請求保留僅訪問新數(shù)據(jù)庫
這里有幾個問題需要探討一下:
首先為什么是先寫新逻恐,然后再遷移存量數(shù)據(jù)呢像吻?
這里考慮切換寫新和遷移數(shù)據(jù)都要做什么。切換寫新复隆,即將寫請求從訪問舊數(shù)據(jù)庫改為訪問新數(shù)據(jù)庫拨匆,這個操作很好完成,只需要改變寫操作的入口即可挽拂。那么數(shù)據(jù)遷移需要做什么呢惭每?我們需要遍歷舊數(shù)據(jù),一條一條地按規(guī)則寫入新的數(shù)據(jù)庫亏栈。由于數(shù)據(jù)遷移往往發(fā)生在發(fā)展了一段時間的舊業(yè)務(wù)上台腥,因此數(shù)據(jù)量一般較大,這個過程也就耗時比較長绒北。
如果先遷移數(shù)據(jù)再切換寫新黎侈,由于遷移數(shù)據(jù)耗時較長,在遷移過程中可能也有新的數(shù)據(jù)寫入闷游,等遷移完切換寫新后峻汉,會存在部分數(shù)據(jù)沒有遷移到新庫中,導致又要再來一次存量數(shù)據(jù)的遷移脐往。因此一般是先切換寫新休吠。
其次是為什么要雙讀呢?
當切換寫新后业簿,數(shù)據(jù)就會部分存在于舊數(shù)據(jù)庫瘤礁,部分存在于新數(shù)據(jù)庫,此時訪問哪個庫梅尤,數(shù)據(jù)都是不完整的柜思,因此需要雙讀來組裝形成完整的數(shù)據(jù)岩调,需要注意的是由于寫操作不僅僅是新增數(shù)據(jù),還會更新/刪除數(shù)據(jù)赡盘,因此雙讀時需要處理好這里的數(shù)據(jù)組裝邏輯誊辉。
這個流程基本可以保障系統(tǒng)能夠不停歇地提供服務(wù),只是需要額外做一些雙讀和切寫的邏輯處理亡脑。只要數(shù)據(jù)遷移的邏輯仔細些,做好對賬邀跃,是能夠做到數(shù)據(jù)不漏不多的霉咨,遷移的時長也能接受較長的時間(只是在此期間的數(shù)據(jù)讀會比較麻煩)。
但是這個流程也存在一個很大的問題拍屑,那就是回退很麻煩途戒。
可以看到,增量數(shù)據(jù)的寫操作只寫入了新數(shù)據(jù)庫僵驰,此時舊數(shù)據(jù)庫是沒有增量數(shù)據(jù)的喷斋,服務(wù)的提供全靠讀操作時把數(shù)據(jù)組裝起來。如果此時發(fā)現(xiàn)新數(shù)據(jù)庫有問題蒜茴,想要退回讀寫舊數(shù)據(jù)庫星爪,就不好回退了。
想要回退粉私,就需要反向來一次類似的數(shù)據(jù)遷移過程:先保持雙讀顽腾,切回寫舊庫,然后將寫入新庫的數(shù)據(jù)遷移回舊庫诺核,再切回讀舊庫抄肖。
為了解決這個問題,就要引出下一個方法:
3.2.2窖杀、在線切換-增量雙寫
顧名思義漓摩,增量雙寫和增量寫新最大的區(qū)別就是,對于新增的數(shù)據(jù)寫入入客,在新舊庫會一起寫管毙。
在新庫寫是為了保障數(shù)據(jù)遷移后數(shù)據(jù)完整,在舊庫寫是為了保障回退時可以直接回退痊项,無需將新數(shù)據(jù)反向遷移回舊庫锅风。
因此整個流程可以描述為:
- 讀舊數(shù)據(jù)
- 開始將增量的寫請求雙寫新舊庫
- 遷移存量數(shù)據(jù)到新庫
- 讀新數(shù)據(jù)
- 停止雙寫,讀新寫新
這里同樣是先啟動雙寫鞍泉,然后再進行數(shù)據(jù)遷移皱埠,原因同前面的增量寫新是一樣的,為了確保不遺漏遷移的數(shù)據(jù)咖驮。
但和前面不同的是边器,這里沒有雙讀训枢,而不是直接從讀舊,切換到讀新忘巧。前面需要雙讀恒界,是因為切換寫新后,舊數(shù)據(jù)庫就沒有新產(chǎn)生的數(shù)據(jù)了砚嘴,需要雙讀來組裝完整的數(shù)據(jù)十酣。而這里因為一直在雙寫,所以實際上舊數(shù)據(jù)一直是有完整數(shù)據(jù)的际长,而遷移完存量數(shù)據(jù)后耸采,新數(shù)據(jù)庫也有了完整的數(shù)據(jù),因此也可以直接切換到讀新工育。
在讀方面虾宇,因為不用雙讀組裝數(shù)據(jù),所以會簡單很多如绸,而且也很好控制灰度過程:只需要確保存量數(shù)據(jù)完整遷移了嘱朽,就可以開始灰度,由于此時新舊數(shù)據(jù)庫都有完整的數(shù)據(jù)怔接,因此可以很方便自由地按任何維度灰度讀新搪泳,也可以隨時回退讀舊。這是它的優(yōu)勢扼脐。
但在寫方面森书,因為要保持雙寫,因此寫邏輯會變得復雜一些谎势。
由于要寫兩份數(shù)據(jù)凛膏,這里首先需要考慮是同步雙寫還是異步雙寫。
和數(shù)據(jù)同步機制類似脏榆,當有寫操作發(fā)生時猖毫,可以選擇是同步將兩個庫都寫成功才算成功,還是只要寫入一個庫成功就算成功须喂,另一個庫通過異步完成寫入吁断。
如果選擇同步雙寫,從結(jié)果上來說是最好的坞生,兩份數(shù)據(jù)是強一致的仔役,如果其中某個庫寫失敗,可以采取某些重試寫入的策略是己,但如果一直失敗又兵,則需要回退另一個寫成功的庫。
如果選擇異步雙寫,寫操作會比較順暢沛厨,省去了寫失敗的回退操作宙地,可以在異步持續(xù)嘗試補償,但缺點是兩份數(shù)據(jù)存在一段時間的不一致逆皮,在切換讀的過程中可能會出現(xiàn)一些異常宅粥。
通常情況下,如果寫入的失敗率極低电谣,則會優(yōu)先選擇同步雙寫秽梅,對寫失敗的情況做一定的重試,如果真的出現(xiàn)極端異常就是無法成功剿牺,又不想或者不方便回退风纠,也可以再補充上異步補償?shù)倪壿嫛?/p>
另外,如果選擇異步雙寫牢贸,還需要考慮的一個點是先寫新數(shù)據(jù)庫還是先寫舊數(shù)據(jù)庫。這決定了哪個數(shù)據(jù)庫是更新更全的數(shù)據(jù)镐捧。
這個選擇同樣需要考慮業(yè)務(wù)場景潜索。
如果數(shù)據(jù)不是用戶自己產(chǎn)生的,用戶只是讀數(shù)據(jù)懂酱,則建議先寫新竹习,因為遷移的過程是從讀舊改為讀新,因此先寫新的情況下列牺,即使舊的沒寫成功或?qū)懲砹苏埃捎谟脩艨床坏剑瑳]有太大影響瞎领,但如果先寫舊成功了泌辫,新的還沒寫,此時切換后會發(fā)現(xiàn)數(shù)據(jù)缺失九默。
如果數(shù)據(jù)是用戶自己產(chǎn)生的震放,則建議優(yōu)先寫舊,用戶在讀舊的時候能立馬看到寫入的數(shù)據(jù)驼修,等遷移到讀新后殿遂,此時離直接寫新時間不會太久,因此看不到寫入的數(shù)據(jù)影響不會太大乙各。
當然墨礁,如果能夠根據(jù)用戶是讀舊還是讀新來決定先寫舊還是先寫新是最好的,但這會導致寫操作的邏輯變得很復雜且難以排查問題耳峦。
4恩静、數(shù)據(jù)遷移的相關(guān)問題
4.1、數(shù)據(jù)版本
如果是在線遷移蹲坷,一定會涉及雙寫蜕企,為了保障數(shù)據(jù)遷移的完整性咬荷,會先開啟雙寫,再遷移存量數(shù)據(jù)幸乒。
在雙寫時,由于新數(shù)據(jù)庫是空的罕扎,因此可以直接寫入/覆蓋丐重。
需要注意的是,對于更新操作扮惦,只會更新部分數(shù)據(jù),此時在新庫寫入時崖蜜,需要取完整的數(shù)據(jù)更新后的數(shù)據(jù)進行寫入,否則未更新的字段會是空值抡柿。
但在遷移存量數(shù)據(jù)的時候,由于此時某條記錄可能已經(jīng)雙寫過新的數(shù)據(jù)洲劣,那么不應(yīng)該被存量數(shù)據(jù)覆蓋。
一種做法是囱稽,在遷移存量時二跋,只要發(fā)現(xiàn)新數(shù)據(jù)庫已經(jīng)有了對應(yīng)記錄的內(nèi)容械哟,就跳過不寫入菠赚。
但如果雙寫和遷移同時進行,此時可能會被誤覆蓋。
另一種做法更保險一點习绢,即對每一條記錄都設(shè)置一個數(shù)據(jù)版本號纠修,在寫操作時淘讥,都需要對比當前想要寫入的數(shù)據(jù)版本號士袄,是否大于等于當前數(shù)據(jù)庫中的數(shù)據(jù)版本號。
如果是襟锐,則說明當前數(shù)據(jù)是更加新的撤逢,可以覆蓋;如果不是,則說明在此過程中發(fā)生了其他寫操作蚊荣,此時不能直接寫入初狰,需要根據(jù)情況決定是放棄還是取最新數(shù)據(jù)來重試更新。
4.2互例、數(shù)據(jù)主鍵
如果數(shù)據(jù)格式做了重新的設(shè)計奢入,此時新數(shù)據(jù)可能會有新的主鍵設(shè)置方式。
比如舊數(shù)據(jù)可能是一個自增ID媳叨,而新數(shù)據(jù)可能會希望設(shè)置一個包含業(yè)務(wù)規(guī)則的有結(jié)構(gòu)的ID(如根據(jù)用戶ID+場景+時間戳+隨機數(shù)組裝新主鍵)腥光。
此時如果直接在數(shù)據(jù)遷移時全部使用新的ID生成方式,那么可能會很難做數(shù)據(jù)對賬糊秆。因為主鍵已經(jīng)不同了武福。
如果在數(shù)據(jù)遷移過程中依然使用舊的ID生成方式,等到遷移完成后再啟用新的方式痘番,雖然可以做對賬捉片,但會導致數(shù)據(jù)存在新舊兩種完全不同的主鍵格式,難以根據(jù)ID做一些切面的操作(如路由規(guī)則)汞舱。
一種可能更適合的解法是伍纫,對新主鍵的ID組裝規(guī)則,設(shè)置一個版本號在其中兵拢,如用戶ID+版本號+場景+時間戳+隨機數(shù)組裝新主鍵。
在數(shù)據(jù)遷移過程中逾礁,使用一個版本(如版本0)嘹履,此時在新主鍵中砾嫉,將舊主鍵的ID組裝進去焕刮。比如格式為:用戶ID+版本號(0)+場景+時間戳+舊ID配并。
等遷移完成后溉旋,修改主鍵生成規(guī)則,并把版本改為1算行,此時新主鍵的格式為:用戶ID+版本號(1)+場景+時間戳+隨機數(shù)州邢。
此時就保障了新數(shù)據(jù)的主鍵全部都是類似的格式偷霉,可以從其中獲取一些信息進行切面操作类少,比如取用戶ID進行路由硫狞。
同時残吩,也可以從中取出舊數(shù)據(jù)的ID泣侮,來做數(shù)據(jù)對賬,并且可以根據(jù)版本來確認哪些記錄是舊數(shù)據(jù)遷移而來需要對賬的記錄漏益。
4.3绰疤、數(shù)據(jù)對賬
數(shù)據(jù)的遷移一定要考慮數(shù)據(jù)能夠容忍的誤差癣猾,是完全不能有誤差煎谍,還是可以容忍缺失數(shù)據(jù)呐粘,或是可以容忍重復數(shù)據(jù),不同的業(yè)務(wù)場景下要求會不一樣唆垃。
但無論要求如何辕万,我們都應(yīng)該對自己遷移的數(shù)據(jù)準確性如何有一個把控渐尿,因此數(shù)據(jù)對賬是必須要做的砖茸。
對賬的工具依托于業(yè)務(wù)當前能夠支持的技術(shù)架構(gòu)凉夯。
如果只能訪問到新舊在線數(shù)據(jù)庫采幌,那么對賬大概只能通過腳本遍歷新舊數(shù)據(jù)進行對比的方式征绎,如磨取,先編譯舊數(shù)據(jù)寝衫,看是否在新的數(shù)據(jù)中全部存在慰毅,再遍歷新數(shù)據(jù)扎阶,看新數(shù)據(jù)是否在舊數(shù)據(jù)中都一致着饥。這里的數(shù)據(jù)訪問需要注意頻率和時間宰掉,避免因為對賬導致太消耗數(shù)據(jù)庫性能,影響線上訪問孟害。另外由于在線數(shù)據(jù)庫中的數(shù)據(jù)一直在隨著用戶的請求產(chǎn)生變化挨务,因此對賬對到什么粒度也是需要根據(jù)業(yè)務(wù)來制定的谎柄。
如果業(yè)務(wù)有離線數(shù)據(jù)倉庫朝巫,則更適合使用離線數(shù)據(jù)進行對賬捍歪,離線數(shù)據(jù)一般是周期性地將在線數(shù)據(jù)庫中的數(shù)據(jù)遷移入庫糙臼,因此數(shù)據(jù)有延遲性变逃,但優(yōu)勢就是它是某個時間分片下的固定數(shù)據(jù)揽乱,不會因為用戶的請求導致數(shù)據(jù)變化凰棉,更好用來確認某個時間下的數(shù)據(jù)是否一致撒犀。
需要注意的是對賬是一個和業(yè)務(wù)的數(shù)據(jù)特性強相關(guān)的事情或舞,不同場景下的對賬邏輯不同映凳,隨著數(shù)據(jù)遷移的策略不同诈豌,對賬方法也不同,不如如果使用停機遷移矫渔,那么數(shù)據(jù)就應(yīng)該是完全一致的铆惑,但如果是增量寫新的策略送膳,則新數(shù)據(jù)一定比舊數(shù)據(jù)更新撕阎。
4.4碌补、灰度切換
無論哪種數(shù)據(jù)遷移策略镇匀,都會涉及一個灰度放量的過程汗侵,避免一把梭訪問新數(shù)據(jù)庫晰韵,導致出現(xiàn)問題時成倍放大雪猪。
一般的灰度過程是:先內(nèi)部白名單用戶進行體驗只恨,然后按照業(yè)務(wù)的特點古劲,設(shè)計灰度規(guī)則产艾,比如根據(jù)用戶比例滑绒,或者用戶類型,或者用戶地域弯菊,進行逐步地灰度放量钦铁。
回滾的過程則與此相反才漆。
在灰度的過程中黎比,需要持續(xù)地觀察監(jiān)控阅虫、日志和數(shù)據(jù)是否符合預期不跟,一旦出現(xiàn)問題躲履,及時進行處理工猜。
這也要求在灰度之前制定詳盡的計劃篷帅,提前考慮可能出現(xiàn)的問題魏身,針對每個可能的問題做好預案箭昵,如何埋點,如何發(fā)現(xiàn)問題回季,如何回退家制,如何補償用戶等正林。
比如,對所有讀寫操作颤殴、新舊數(shù)據(jù)庫的讀寫請求情況進行埋點觅廓,確認能了解灰度的進程以及灰度范圍是否符合預期;定期對賬及時發(fā)現(xiàn)數(shù)據(jù)出入涵但;遷移完成后可以雙讀并進行數(shù)據(jù)對比一致性告警一段時間等等杈绸。
很多系統(tǒng)會提供按流量比例灰度放量的能力矮瘟,但是要根據(jù)業(yè)務(wù)特性設(shè)置更符合業(yè)務(wù)要求的灰度維度,則可能需要特殊開發(fā)設(shè)計棘催。
比如如果需要根據(jù)用戶地域灰度呼猪,則大致需要這些步驟:
- 如果涉及前端變動,特別是APP/小程序的,需要提前發(fā)版支持查詢后臺確認當前用戶展示的前端頁面版本
- 開發(fā)根據(jù)需要的維度按名單/比例篩選用戶的能力
- 提供根據(jù)用戶確認前端展示版本與新舊數(shù)據(jù)的接口
- 在后臺讀寫接口中支持根據(jù)3的接口返回的信息選擇讀寫策略
4.5闸盔、接口兼容
數(shù)據(jù)遷移不僅僅是簡單的換一個數(shù)據(jù)庫使用茴肥,有時候如果數(shù)據(jù)的變化特別大(如數(shù)據(jù)結(jié)構(gòu)础锐、使用方式都變了)信姓,那么還會影響數(shù)據(jù)讀寫的接口格式。
如果涉及到提供給其他系統(tǒng)的接口,由于其他系統(tǒng)的開發(fā)人員不一定能夠跟隨我方的數(shù)據(jù)遷移安排進行接口調(diào)用的變動,因此這里存在一個接口兼容的問題典徊。
接口兼容不完全等同于雙寫儡毕。
首先即使是停機遷移费坊,如果涉及數(shù)據(jù)接口的變化即接口的變化永毅,一樣會有接口兼容的問題滨嘱。
其次一般雙寫的話,更好做雙寫的入口是在新接口细移,即對新接口的協(xié)議做好設(shè)計精绎,使其能夠滿足新舊數(shù)據(jù)格式的訴求吭历,然后將寫請求轉(zhuǎn)發(fā)到新舊兩個庫契讲。
而舊接口由于僅針對當時的舊數(shù)據(jù)格式設(shè)計傅物,可能無法滿足新數(shù)據(jù)格式的需要。
但如果其他調(diào)用我們寫接口的系統(tǒng)無法在我們上線前完成調(diào)整崎场,則其依然會調(diào)用舊接口,此時我們只能從舊接口進行雙寫,就需要我們在舊接口對新接口需要的內(nèi)容做好兼容。
此時需要我們對新舊接口需要的數(shù)據(jù)進行分析對比酣倾,找出字段間的對應(yīng)關(guān)系,對于舊接口沒有而新接口需要的內(nèi)容抬伺,需要明確一個默認值寞宫。
當然這個過程不要持續(xù)太久悟民,最好明確一個接口的遷移截止時間,推動其他調(diào)用的系統(tǒng)按期完成從舊到新接口的調(diào)整,才能獲取到最準確的新數(shù)據(jù)。
4.6知态、臟數(shù)據(jù)
舊數(shù)據(jù)之所以舊捷兰,是因為從過去運行了一段時間,而在這個過程中负敏,可能隨著業(yè)務(wù)發(fā)展贡茅,對數(shù)據(jù)結(jié)構(gòu)和使用方式進行了很多調(diào)整,比如新增了字段其做、新增了數(shù)據(jù)校驗規(guī)則顶考、新增了數(shù)據(jù)間的依賴關(guān)系等。
而在新增這些數(shù)據(jù)妖泄、規(guī)則驹沿、關(guān)系之前的數(shù)據(jù)中,這些內(nèi)容可能是空的蹈胡、不滿足規(guī)范的渊季。因此在數(shù)據(jù)遷移的過程中朋蔫,極可能遇到一些不符合預期的“臟數(shù)據(jù)”。
這些臟數(shù)據(jù)却汉,都會影響我們的數(shù)據(jù)遷移進程斑举,如果沒有進行恰當?shù)奶幚恚瑯O有可能導致數(shù)據(jù)遷移失敗病涨、不完整富玷,而如果我們的遷移時間比較緊張,就更可能會忙中出錯既穆。
要規(guī)避這個問題赎懦,有兩個應(yīng)對手段。
第一幻工,盡量減少所要遷移的歷史數(shù)據(jù)時間跨度励两,只遷移最近一段時間的數(shù)據(jù)。
前面分析過囊颅,數(shù)據(jù)是隨著業(yè)務(wù)的發(fā)展不斷規(guī)范的当悔,因此越靠近當下的數(shù)據(jù),越規(guī)范踢代,越古早的數(shù)據(jù)盲憎,則越可能因為規(guī)范的缺失,出現(xiàn)臟亂差的局面胳挎。
因此如果可以饼疙,盡量減少需要遷移的數(shù)據(jù)時間,這樣需要特殊處理的臟數(shù)據(jù)會更少慕爬。
而對于需要完整歷史數(shù)據(jù)的場景窑眯,可以通過其他手段提供,比如保留舊數(shù)據(jù)庫医窿,但僅提供離線訪問場景磅甩,只用于需要查詢歷史數(shù)據(jù)的情況,而且不提供在線查詢姥卢,并從業(yè)務(wù)規(guī)則上卷要,限制對過于久遠的歷史數(shù)據(jù)的寫操作。
最極端的隔显,是完全不遷移歷史數(shù)據(jù)却妨,這適合一些對于歷史數(shù)據(jù)的可讀寫時間很短的業(yè)務(wù),可以通過延長雙寫時間括眠,讓新數(shù)據(jù)庫擁有需要提供讀寫的短期新數(shù)據(jù)彪标,而更久遠的數(shù)據(jù),一概不提供讀寫掷豺,就可以做到完全能不遷移捞烟。
第二薄声,是提前摸排數(shù)據(jù),掌握臟數(shù)據(jù)的分布情況题画,和產(chǎn)品同學溝通臟數(shù)據(jù)的處理手段默辨,盡量規(guī)避在數(shù)據(jù)遷移的過程中出現(xiàn)不可預知的無法處理的臟數(shù)據(jù),導致影響數(shù)據(jù)遷移過程苍息。
比如一個枚舉字段缩幸,按當前的規(guī)范應(yīng)該有四種可能的枚舉值,但歷史數(shù)據(jù)可能有一些無數(shù)據(jù)或其他枚舉值的情況竞思,此時只能通過對歷史數(shù)據(jù)的摸排去看到底有沒有表谊,如果有,需要溝通合適的處理方法盖喷, 比如在新數(shù)據(jù)中對不屬于四種合理值的情況都默認設(shè)為某個值爆办。
最極端和簡單的做法,是對所有字段课梳,明確一個遷移的檢查規(guī)則距辆,不符合規(guī)則的,就都設(shè)置一個兜底的默認值暮刃,這樣可以規(guī)避大部分問題跨算。
通常情況下,上述兩種方法需要共同使用沾歪。第一個方法可以極大減少工作量漂彤,第二個方法可以極大減少異常出現(xiàn)的概率雾消。
5數(shù)據(jù)遷移的質(zhì)量評估
5.1灾搏、完整性
完整性是指數(shù)據(jù)應(yīng)該有新數(shù)據(jù)的邏輯規(guī)范所要求的所有必要屬性。
舊數(shù)據(jù)由于歷史的發(fā)展迭代立润,可能存在大量數(shù)據(jù)內(nèi)容的缺失狂窑,此時就需要有默認的規(guī)則對其進行補齊。
還需保障有明確的規(guī)則來評估新數(shù)據(jù)在新規(guī)則上是完整的桑腮。
5.2泉哈、唯一性
新數(shù)據(jù)在新的規(guī)則下,要維持自己的記錄唯一性破讨,這個唯一性和舊數(shù)據(jù)可能相同丛晦,也可能不同。
也許舊數(shù)據(jù)出于歷史原因提陶,會存在重復的數(shù)據(jù)烫沙,那么在新數(shù)據(jù)下,要有合理手段保障只保留唯一有效的記錄(唯一鍵隙笆、冪等性)锌蓄。
5.3升筏、及時性
數(shù)據(jù)的遷移一定涉及存量數(shù)據(jù)遷移和增量數(shù)據(jù)同步的問題,對于存量數(shù)據(jù)很好做到仔細的核對瘸爽,但同時也要保障增量數(shù)據(jù)的及時同步您访。
數(shù)據(jù)從產(chǎn)生,到能被消費剪决,需要保障新數(shù)據(jù)和舊數(shù)據(jù)的延遲盡量低灵汪,以滿足業(yè)務(wù)在數(shù)據(jù)遷移期間的正常數(shù)據(jù)訴求。
5.4柑潦、合法性
無論新數(shù)據(jù)還是舊數(shù)據(jù)识虚,其實都應(yīng)該保障數(shù)據(jù)合法,所謂的合法妒茬,既是指要符合業(yè)務(wù)的邏輯(比如訂單數(shù)據(jù)內(nèi)一定應(yīng)該包含商戶信息)担锤,也是指要符合數(shù)據(jù)字段本身的要求,比如常見的電話號碼乍钻、郵箱格式肛循,或者業(yè)務(wù)特定的數(shù)據(jù)格式。
對于舊數(shù)據(jù)的不符合規(guī)范的數(shù)據(jù)银择,要有排查摸底多糠,以及合理的篩選發(fā)現(xiàn)邏輯與處理規(guī)則。
對于增量數(shù)據(jù)的寫入浩考,則應(yīng)當經(jīng)過嚴格的數(shù)據(jù)校驗夹孔。
5.5、一致性
一致性很好理解析孽,新數(shù)據(jù)和舊數(shù)據(jù)通常來說應(yīng)該是能一一對應(yīng)上的(重復數(shù)據(jù)除外)搭伤。數(shù)據(jù)對賬是一種常見的一致性比對方式。
但除了舊數(shù)據(jù)袜瞬,在特定業(yè)務(wù)場景下怜俐,新數(shù)據(jù)最好還能夠保障和真正的數(shù)據(jù)源(上游數(shù)據(jù)來源)做到一致性,這是因為數(shù)據(jù)最終是為了業(yè)務(wù)服務(wù)的邓尤,如果和上游數(shù)據(jù)不一致拍鲤,則會導致業(yè)務(wù)流程中出現(xiàn)錯漏的情況,而舊數(shù)據(jù)本身和上游汞扎,并不一定保障了一致性季稳。
6、小結(jié)
關(guān)于數(shù)據(jù)遷移澈魄,由于變化太劇烈景鼠,而且可以造成的影響太大,因此無論對細節(jié)思考到何種程度都是不為過的一忱,本文也僅是記錄下我在工作中思考的內(nèi)容莲蜘,實際上在每個業(yè)務(wù)的數(shù)據(jù)遷移過程中谭确,都可能會有特殊的需要注意的地方。也引用三體中的一句話來結(jié)尾:
章父:要多想
章北海:想了以后呢票渠?
章父:北海逐哈,我只能告訴你在那以前要多想
——《三體》