生產(chǎn)環(huán)境數(shù)據(jù)庫表遷移實(shí)戰(zhàn)

數(shù)據(jù)庫表遷移是開發(fā)者必須要掌握的一種能力益缠,對中高級開發(fā)者來說更是如此割笙。工作中隨著公司業(yè)務(wù)不斷發(fā)展、系統(tǒng)架構(gòu)的慢慢調(diào)整演化识虚,遷移數(shù)據(jù)庫表是不可避免的。由于數(shù)據(jù)是公司最最核心的資產(chǎn)妒茬,所以對生產(chǎn)環(huán)境數(shù)據(jù)庫表的遷移并不是誰都可以去實(shí)施操作的担锤,所以你會發(fā)現(xiàn)很多人其實(shí)對數(shù)據(jù)庫表的遷移并沒有相關(guān)思路,因?yàn)槿鄙賹?shí)踐的機(jī)會乍钻,初次承擔(dān)這樣的任務(wù)時(shí)會有些不太自信肛循,因?yàn)椴恢雷约旱奶幚砹鞒淌欠癜踩煽浚吘箶?shù)據(jù)上的問題一般都是很嚴(yán)重的银择。

本文以實(shí)際開發(fā)中的項(xiàng)目為背景多糠,盡量全面的分享給你生產(chǎn)環(huán)境中數(shù)據(jù)庫表的遷移思路及遷移實(shí)踐。注意:數(shù)據(jù)庫表遷移和你自己的業(yè)務(wù)有強(qiáng)關(guān)聯(lián)性浩考,比如業(yè)務(wù)的高低峰時(shí)間夹孔、業(yè)務(wù)可容忍的短時(shí)寫不可用的程度,等等析孽,自己負(fù)責(zé)遷移時(shí)必須具體問題具體分析搭伤。

OK,直奔主題~

場景模型一:庫1(源庫)只有一個(gè)服務(wù)使用

之前負(fù)責(zé)的服務(wù)中有個(gè)老服務(wù)袜瞬,這里我們稱之為service_A怜俐,歷史原因這個(gè)服務(wù)中
配置了兩個(gè)數(shù)據(jù)源,連接了兩個(gè)數(shù)據(jù)庫吞滞。在公司微服務(wù)化的系統(tǒng)架構(gòu)中佑菩,隨著各服務(wù)各系統(tǒng)邊界的清晰和穩(wěn)定,service_A使用兩個(gè)庫就變得多余裁赠,浪費(fèi)系統(tǒng)資源

同時(shí)也增加了維護(hù)成本殿漠。總之就是需要把service_A回歸為使用單庫佩捞。所以绞幌,自然就要把一個(gè)庫表(這里我們稱為庫1)遷移到另一個(gè)庫(這里我們稱為庫2),如下圖:
img.png

OK一忱,明白了我們的訴求之后莲蜘,接下來說下生產(chǎn)環(huán)境中的遷移方法:

tips: 遷移請選在業(yè)務(wù)的低峰日的低峰時(shí)間去實(shí)施,遷移的核心是要保證數(shù)據(jù)的一致性帘营!

遷移步驟:

遷移實(shí)施前的處理流程:

1.開發(fā)工程師在業(yè)務(wù)系統(tǒng)也就是微服務(wù)中catch數(shù)據(jù)庫相關(guān)異常票渠,如Java服務(wù),那就在項(xiàng)目的統(tǒng)一切面中做處理:優(yōu)點(diǎn)是不會侵入業(yè)務(wù)代碼芬迄;或者添加開關(guān):顧名思義要在業(yè)務(wù)邏輯所在的接口中添加问顷,可能需要改動(dòng)多處,并給出友好提示禀梳,比如如下的簡單處理:

@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(MySQLSyntaxErrorException.class)
    void exception(MySQLSyntaxErrorException ex) {
        log.error(StringUtils.EMPTY, ex);
        throw new RuntimeException("系統(tǒng)升級中請稍后再試");
    }

    @ExceptionHandler(BadSqlGrammarException.class)
    void exception(BadSqlGrammarException ex) {
        log.error(StringUtils.EMPTY, ex);
        throw new RuntimeException("系統(tǒng)升級中請稍后再試");
    }
    
    @ExceptionHandler(BadSqlGrammarException.class)
    void exception(CommunicationsException ex) {
        log.error(StringUtils.EMPTY, ex);
        throw new RuntimeException("系統(tǒng)升級中請稍后再試");
    }
}

改完測試OK之后將代碼發(fā)布到生產(chǎn)環(huán)境杜窄,本步驟本質(zhì)是遷移前的
預(yù)處理階段

2.通知測試提前造一些線上需要驗(yàn)證的數(shù)據(jù),方便遷移時(shí)快速驗(yàn)證

遷移實(shí)施時(shí)的流程:

1.創(chuàng)建源庫(庫1)到目標(biāo)庫(庫2)的實(shí)時(shí)同步的任務(wù)(全量+增量)算途,如果你們公司用的是云廠商提供的RDS塞耕,可以用他們提供的DTS工具去做同步,如果是自建的IDC嘴瓤,那么可以通過canal等開源工具去做同步扫外;請?zhí)崆霸u估待同步的數(shù)據(jù)量,大數(shù)據(jù)量時(shí)可能耗時(shí)一周甚至更多(中大型公司廓脆,此步驟由DBA實(shí)施)

2.提供目標(biāo)庫的只讀賬號畏浆、密碼(中大型公司,此步驟由DBA實(shí)施)

3.檢查源庫和目標(biāo)庫之間是否還有DTS同步任務(wù)(canal同步信息)狞贱,且是否已經(jīng)同步到最新刻获,DBA將結(jié)果通知開發(fā)(中大型公司,此步驟由DBA實(shí)施)

4.在配置中心中如Apollo瞎嬉、nacos等將連接源庫的url切換到目標(biāo)庫蝎毡,

源庫賬號、密碼替換為第二步目標(biāo)庫的只讀賬號氧枣、密碼, 配置發(fā)布后沐兵,重啟自己的服務(wù)。注意便监,服務(wù)重啟之后系統(tǒng)對源庫表的寫操作已經(jīng)不支持, 支持可讀扎谎。若此時(shí)有零星的寫操作打到系統(tǒng)中碳想,我們系統(tǒng)就會提示我們前面給的提示信息:系統(tǒng)升級中,請稍后再試毁靶。本步驟示意圖如下:
img_2.png

修改配置中心的數(shù)據(jù)庫連接配置
img_1.png

5.再次檢查源庫流量(確保源庫無流量胧奔,二次確認(rèn)),然后關(guān)閉實(shí)時(shí)同步任務(wù)预吆,DBA通知開發(fā)

6.修改配置中心中源庫賬號龙填,使用目標(biāo)庫的賬號(正常的讀寫賬號),發(fā)布配置,重啟服務(wù)拐叉,使用提前造好的測試數(shù)據(jù)驗(yàn)證遷移表的讀寫是否都正常岩遗;操做驗(yàn)證相關(guān)核心流程的讀寫都OK就可以了

7.數(shù)據(jù)遷移結(jié)束,可以睡覺了

遷移后續(xù)處理流程

遷移結(jié)束后凤瘦,你可以排期進(jìn)行如下的后續(xù)清理操作:

  1. 刪除項(xiàng)目中關(guān)于源數(shù)據(jù)庫的配置宿礁,服務(wù)回歸單數(shù)據(jù)源,

  2. 刪除配置中心上關(guān)于源數(shù)據(jù)庫的配置

  3. 測試驗(yàn)證通過后,發(fā)布生產(chǎn)蔬芥,結(jié)束

當(dāng)然這個(gè)后續(xù)處理流程你也可以直接在步驟6中做掉窘拯,我習(xí)慣于拆解問題,分開處理坝茎。

遷移總結(jié):

1.可以發(fā)現(xiàn)上述遷移過程對源庫表是存在短暫停寫的涤姊,步驟4執(zhí)行之后寫操作影響開始,步驟6執(zhí)行之后恢復(fù)正常嗤放。整個(gè)過程前期演練好思喊,實(shí)際上耗時(shí)很短,2分鐘左右的時(shí)間

2.正因?yàn)榉桨赣型懙牟僮鞔巫茫源朔桨覆粫嬖谶w移前后數(shù)據(jù)不一致的問題恨课,
沒有數(shù)據(jù)的一致性問題,是這個(gè)方案的優(yōu)點(diǎn)

3.生產(chǎn)環(huán)境實(shí)施前岳服,請?jiān)趂at剂公、uat等環(huán)境認(rèn)真嚴(yán)格的演練

場景模型二:庫中的表被兩個(gè)不同的服務(wù)使用

庫中的表被兩個(gè)不同的服務(wù)使用,這是我們系統(tǒng)在不斷演化中最常見的場景,

一服一庫吊宋,總之我們一般都會進(jìn)行庫表分離纲辽,也就是庫表遷移了
img_3.png

遷移步驟:

遷移實(shí)施前的處理流程:

1.項(xiàng)目中給出友好提示(具體描述請看場景一)

2.測試造測試數(shù)據(jù)(具體描述請看場景一)

3.DBA創(chuàng)建一個(gè)源庫新的賬號,修改服務(wù)A的配置中心的數(shù)據(jù)庫連接的用戶名璃搜。此步驟非常重要拖吼,我們要把服務(wù)A和服務(wù)B連接源庫的賬號分開,這樣在遷移實(shí)施時(shí)我們才能確定源庫中是否還有服務(wù)A的流量这吻,用于判定是否可以關(guān)閉源庫和目標(biāo)庫的
同步任務(wù)吊档。如果服務(wù)A和B使用的賬號一樣,將無法確認(rèn)唾糯,因?yàn)槲覀冞w移時(shí)服務(wù)B始終是在正常工作的

我們可以通過這個(gè)命令查看庫連接情況:SHOW PROCESSLIST;
img_4.png

遷移實(shí)施時(shí)的流程:

1.創(chuàng)建源庫到目標(biāo)庫的實(shí)時(shí)同步任務(wù)(全量+增量)

2.提供目標(biāo)庫的只讀賬號怠硼、密碼

3.檢查源庫和目標(biāo)庫之間是否還有DTS同步任務(wù)(canal同步信息)鬼贱,且是否已經(jīng)同步到最新,DBA將結(jié)果通知開發(fā)

4.在配置中心中將連接源庫的url切換到目標(biāo)庫香璃,源庫賬號这难、密碼替換為第二步目標(biāo)庫的只讀賬號、密碼, 配置發(fā)布后增显,重啟自己的服務(wù)。注意脐帝,服務(wù)重啟之后系統(tǒng)對源庫表的寫操作已經(jīng)不支持, 支持可讀同云。若此時(shí)有零星的寫操作打到系統(tǒng)中,我們系統(tǒng)就會提示我們前面給的提示信息:系統(tǒng)升級中堵腹,請稍后再試炸站。

5.再次檢查源庫中服務(wù)A賬號的流量(確保源庫相關(guān)賬號無流量,二次確認(rèn))疚顷,然后關(guān)閉實(shí)時(shí)同步任務(wù)旱易,DBA通知開發(fā)

6.修改服務(wù)A配置中心中源庫賬號,使用目標(biāo)庫的讀寫賬號,發(fā)布配置腿堤,重啟服務(wù)阀坏,
使用提前造好的測試數(shù)據(jù)驗(yàn)證遷移表的讀寫是否都正常;操做驗(yàn)證相關(guān)核心流程的讀寫都OK就可以了

遷移結(jié)束笆檀,睡覺...

遷移后續(xù)處理流程

后續(xù)可以將源庫中服務(wù)A的表清理掉

遷移總結(jié):

遷移總結(jié)同場景一

分析總結(jié)

上述兩個(gè)方案基本可以解決我們?nèi)粘4蠖鄶?shù)的遷移需求忌堂,優(yōu)點(diǎn)就是簡單易實(shí)施且不存在數(shù)據(jù)的一致性問題,可靠酗洒,不足就是存在短暫的不可寫士修。在實(shí)際遷移時(shí)建議優(yōu)先考慮這種方案,因?yàn)楹唵魏涂煽繎?yīng)該是我們的首選

雙寫方案

如果我們的系統(tǒng)完全不能接受停寫(即使是在低峰期)那怎么辦呢樱衷,需要我們怎么遷移庫表棋嘲?針對這種情況業(yè)界一般使用所謂的:雙寫方案。雙寫方案是指遷移中我們不會暫停系統(tǒng)的寫入能力且同時(shí)寫入源庫和目標(biāo)庫矩桂,具體實(shí)施步驟如下:

1.創(chuàng)建源庫到目標(biāo)庫的同步任務(wù)沸移,全量+增量,等待目標(biāo)庫追平源庫表數(shù)據(jù)

2.項(xiàng)目改動(dòng)侄榴,修改系統(tǒng)代碼阔籽,支持寫源庫的同時(shí)也要寫入目標(biāo)庫,寫目標(biāo)庫可以使用異步的方式牲蜀,建議使用MQ笆制,mq異步、解耦的同時(shí)也具有重試的機(jī)制涣达,當(dāng)然重試之后仍然失敗在辆,那么需要保存失敗記錄证薇,以便后續(xù)手動(dòng)維護(hù)數(shù)據(jù)。同時(shí)系統(tǒng)中需要添加開關(guān)用于控制何時(shí)開始異步寫入目標(biāo)庫匆篓,開關(guān)默認(rèn)關(guān)閉

3.數(shù)據(jù)追平之后浑度,在業(yè)務(wù)低峰時(shí)間開始實(shí)施遷移的核心操作,關(guān)閉源庫到目標(biāo)庫的同步任務(wù)同時(shí)立即打開第二步中設(shè)置的開關(guān)鸦概,這樣系統(tǒng)就開始同步寫源庫和目標(biāo)庫(異步方式)了箩张;注意關(guān)閉同步任務(wù)并立即打開設(shè)置的開關(guān)這個(gè)地方雖然耗時(shí)
很短(秒級),但是可能也會造成源庫和目標(biāo)庫數(shù)據(jù)的不一致窗市。

4.系統(tǒng)的雙寫打開之后先慷,接著需要我們檢查源庫表和目標(biāo)庫表中的數(shù)據(jù)是否一致,此步驟是重中之重咨察,關(guān)系到遷移是否成功论熙。發(fā)現(xiàn)有不一致的數(shù)據(jù),需要我們手動(dòng)維護(hù)使之一致摄狱。如果發(fā)現(xiàn)數(shù)據(jù)嚴(yán)重不一致脓诡,那就再關(guān)閉開關(guān),遷移失敗媒役。

5.源庫和目標(biāo)庫兩邊數(shù)據(jù)一致后祝谚,我們需要修改系統(tǒng)和配置中心的配置,讓系統(tǒng)從目標(biāo)庫讀酣衷,雙寫不變踊跟;由于是異步寫目標(biāo)庫,所以此時(shí)讀可能存在延時(shí)(一般為毫秒級)

6.檢查系統(tǒng)核心流程讀寫是否正常鸥诽,然后修改系統(tǒng)代碼商玫、配置中心配置,使讀寫都走目標(biāo)庫牡借,同時(shí)關(guān)閉異步寫目標(biāo)庫

7.再次檢查系統(tǒng)的讀寫是否正常拳昌,源庫、目標(biāo)庫數(shù)據(jù)是否一致

結(jié)束
img_5.png
img_6.png
img_7.png

雙寫方案總結(jié)

1.遷移中沒有停寫的要求

2.正因?yàn)闆]有停寫钠龙,所以可能導(dǎo)致源庫和目標(biāo)庫數(shù)據(jù)的不一致炬藤,需要嚴(yán)格校驗(yàn)數(shù)據(jù)的一致性

3.代碼改動(dòng)會較多,且需考慮周到

4.若沒有必須的理由建議不使用該方案

OK碴里,結(jié)束沈矿,咱們回聊~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市咬腋,隨后出現(xiàn)的幾起案子羹膳,更是在濱河造成了極大的恐慌,老刑警劉巖根竿,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陵像,死亡現(xiàn)場離奇詭異就珠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)醒颖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門妻怎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泞歉,你說我怎么就攤上這事逼侦。” “怎么了腰耙?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵榛丢,是天一觀的道長。 經(jīng)常有香客問我沟优,道長涕滋,這世上最難降的妖魔是什么睬辐? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任挠阁,我火速辦了婚禮,結(jié)果婚禮上溯饵,老公的妹妹穿的比我還像新娘侵俗。我一直安慰自己,他們只是感情好丰刊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布隘谣。 她就那樣靜靜地躺著,像睡著了一般啄巧。 火紅的嫁衣襯著肌膚如雪寻歧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天秩仆,我揣著相機(jī)與錄音码泛,去河邊找鬼。 笑死澄耍,一個(gè)胖子當(dāng)著我的面吹牛噪珊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播齐莲,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼痢站,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了选酗?” 一聲冷哼從身側(cè)響起阵难,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芒填,沒想到半個(gè)月后多望,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫩舟,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年怀偷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了家厌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椎工,死狀恐怖饭于,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情维蒙,我是刑警寧澤掰吕,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站颅痊,受9級特大地震影響殖熟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斑响,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一菱属、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舰罚,春花似錦纽门、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饲漾,卻和暖如春蝙搔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背考传。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工吃型, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伙菊。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓败玉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親镜硕。 傳聞我的和親對象是個(gè)殘疾皇子运翼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容