引言
我們先來(lái)講一個(gè)段子
面試官:“有并發(fā)的經(jīng)驗(yàn)沒(méi)奕坟?”
應(yīng)聘者:“有一點(diǎn)祥款∏灞浚”
面試官:“那你們?yōu)榱颂幚聿l(fā),做了哪些優(yōu)化刃跛?”
應(yīng)聘者:“前后端分離啊抠艾,限流啊,分庫(kù)分表啊桨昙。检号。”
面試官:"談?wù)劮謳?kù)分表吧绊率?"
應(yīng)聘者:“bala谨敛。bala。bala滤否。脸狸。”
面試官心理活動(dòng):這個(gè)仁兄講的怎么這么像網(wǎng)上的博客抄的藐俺,容我再問(wèn)問(wèn)炊甲。
面試官:“你們分庫(kù)分表后,如何部署上線的欲芹?”
應(yīng)聘者:“這G浞取!A飧浮>蹦取!浙宜!”
在網(wǎng)上看了很多關(guān)于 分庫(kù)分表的文章官辽,很神奇的是,都在講怎么進(jìn)行分庫(kù)分表粟瞬,卻不說(shuō)分完以后同仆,怎么部署上線的。這樣在面試的時(shí)候就比較尷尬了裙品。
你們自己摸著良心想一下俗批,如果你真的做過(guò)分庫(kù)分表,你會(huì)不知道如何部署的么市怎?因此我們來(lái)學(xué)習(xí)一下如何部署吧岁忘。
ps:
我發(fā)現(xiàn)一個(gè)很神奇的現(xiàn)象。因?yàn)楹芏喙居玫募夹g(shù)比較low区匠,那么一些求職者為了提高自己的競(jìng)爭(zhēng)力臭觉,就會(huì)將一些高大上的技術(shù)寫(xiě)進(jìn)自己的low項(xiàng)目中。然后呢,他出去面試害怕碰到從這個(gè)公司出來(lái)的人蝠筑,畢竟從這個(gè)公司出來(lái)的人狞膘,一定知道自己以前公司的項(xiàng)目情形。因此為了圓謊什乙,他就會(huì)說(shuō):“他們從事的是這個(gè)公司的老項(xiàng)目改造工作挽封,用了很多新技術(shù)進(jìn)去!”
那么臣镣,請(qǐng)你好好思考一下辅愿,你們的老系統(tǒng)是如何平滑升級(jí)為新系統(tǒng)的!
如何部署
停機(jī)部署法
大致思路就是忆某,掛一個(gè)公告点待,半夜停機(jī)升級(jí),然后半夜把服務(wù)停了弃舒,跑數(shù)據(jù)遷移程序癞埠,進(jìn)行數(shù)據(jù)遷移。
步驟如下:
(1)出一個(gè)公告聋呢,比如“今晚00:00~6:00進(jìn)行停機(jī)維護(hù)苗踪,暫停服務(wù)”
(2)寫(xiě)一個(gè)遷移程序,讀db-old
數(shù)據(jù)庫(kù)削锰,通過(guò)中間件寫(xiě)入新庫(kù)db-new1
和db-new2
通铲,具體如下圖所示
(3)校驗(yàn)遷移前后一致性,沒(méi)問(wèn)題就切該部分業(yè)務(wù)到新庫(kù)器贩。
順便科普一下颅夺,這個(gè)中間件。現(xiàn)在流行的分庫(kù)分表的中間件有兩種蛹稍,一種是proxy
形式的吧黄,例如mycat
,是需要額外部署一臺(tái)服務(wù)器的稳摄。還有一種是client
形式的,例如當(dāng)當(dāng)出的Sharding-JDBC
饲宿,就是一個(gè)jar包厦酬,使用起來(lái)十分輕便。我個(gè)人偏向Sharding-JDBC
瘫想,這種方式仗阅,無(wú)需額外部署,無(wú)其他依賴国夜,DBA也無(wú)需改變?cè)械倪\(yùn)維方式减噪。
評(píng)價(jià):
大家不要覺(jué)得這種方法low,我其實(shí)一直覺(jué)得這種方法可靠性很強(qiáng)。而且我相信各位讀者所在的公司一定不是什么很牛逼的互聯(lián)網(wǎng)公司筹裕,如果你們的產(chǎn)品凌晨1點(diǎn)的用戶活躍數(shù)還有超過(guò)1000的醋闭,你們握個(gè)爪!畢竟不是所有人都在什么電商公司的朝卒,大部分產(chǎn)品半夜都沒(méi)啥流量证逻。所以此方案,并非沒(méi)有可取之處抗斤。
但是此方案有一個(gè)缺點(diǎn)囚企,累!不止身體累瑞眼,心也累龙宏!你想想看,本來(lái)定六點(diǎn)結(jié)束伤疙,你五點(diǎn)把數(shù)據(jù)庫(kù)遷移好银酗,但是不知怎么滴,程序切新庫(kù)就是有點(diǎn)問(wèn)題掩浙。于是花吟,眼瞅著天就要亮了,趕緊把數(shù)據(jù)庫(kù)切回老庫(kù)厨姚。第二個(gè)晚上繼續(xù)這么干衅澈,簡(jiǎn)直是身心俱疲。
ps:
這里教大家一些技巧啊谬墙,如果你真的沒(méi)做過(guò)分庫(kù)分表今布,又想吹一波,漲一下工資拭抬,建議答這個(gè)方案部默。因?yàn)檫@個(gè)方案比較low,low到?jīng)]什么東西可以深挖的造虎,所以答這個(gè)方案傅蹂,比較靠譜。
另外算凿,如果面試官的問(wèn)題是
你們?cè)趺催M(jìn)行分庫(kù)分表的份蝴?
這個(gè)問(wèn)題問(wèn)的很泛,所以回答這個(gè)問(wèn)題建議自己主動(dòng)把分表的策略氓轰,以及如何部署的方法講出來(lái)婚夫。因?yàn)檫@么答,顯得嚴(yán)謹(jǐn)一些署鸡。
不過(guò)案糙,很多面試官為了賣(mài)弄自己的技術(shù)限嫌,喜歡這么問(wèn)
分表有哪些策略啊时捌?你們用哪種芭健?
ok匣椰。裆熙。這個(gè)問(wèn)題具體指向了分庫(kù)分表的某個(gè)方向了,你不要主動(dòng)答如何進(jìn)行部署的禽笑。等面試官問(wèn)你入录,你再答。如果面試官?zèng)]問(wèn)佳镜,在面試最后一個(gè)環(huán)節(jié)僚稿,面試官會(huì)讓你問(wèn)讓幾個(gè)問(wèn)題。你就問(wèn)
你剛才剛好有提到分庫(kù)分表的相關(guān)問(wèn)題蟀伸,我們當(dāng)時(shí)部署的時(shí)候蚀同,先停機(jī)。然后半夜遷移數(shù)據(jù)啊掏,然后第二天將流量切到新庫(kù)蠢络,這種方案太累,不知道貴公司有沒(méi)有什么更好的方案迟蜜?
那么這種情況下刹孔,面試官會(huì)有兩種回答。第一種娜睛,面試官硬著頭皮隨便扯髓霞。第二種,面試官真的做過(guò)畦戒,據(jù)實(shí)回答方库。記住,面試官怎么回答的不重要障斋。重點(diǎn)的是纵潦,你這個(gè)問(wèn)題出去,會(huì)給面試官一種錯(cuò)覺(jué):"這個(gè)小伙子真的做過(guò)分庫(kù)分表垃环。"
如果你擔(dān)心進(jìn)去了邀层,真派你去做分庫(kù)分表怎么辦?OK晴裹,不要怕被济。我賭你試用期碰不到這個(gè)活救赐。因?yàn)槟苓M(jìn)行分庫(kù)分表涧团,必定對(duì)業(yè)務(wù)非常熟只磷。還在試用期的你,必定對(duì)業(yè)務(wù)不熟泌绣,如果領(lǐng)導(dǎo)給你這種活钮追,我只能說(shuō)他有一顆大心臟。
ok阿迈,指點(diǎn)到這里元媚。面試本來(lái)就是一場(chǎng)斗智斗勇的過(guò)程,扯遠(yuǎn)了苗沧,回到我們的主題刊棕。
雙寫(xiě)部署法(一)
這個(gè)就是不停機(jī)部署法,這里我需要先引進(jìn)兩個(gè)概念:歷史數(shù)據(jù)和增量數(shù)據(jù)待逞。
假設(shè)甥角,我們是對(duì)一張叫做test_tb
的表進(jìn)行拆分,因?yàn)槟阋M(jìn)行雙寫(xiě)识樱,系統(tǒng)里頭和test_tb
表有關(guān)的業(yè)務(wù)之前必定會(huì)加入一段雙寫(xiě)代碼嗤无,同時(shí)往老庫(kù)和新庫(kù)中寫(xiě),然后進(jìn)行部署怜庸,那么
歷史數(shù)據(jù):在該次部署前当犯,數(shù)據(jù)庫(kù)表test_tb
的有關(guān)數(shù)據(jù),我們稱(chēng)之為歷史數(shù)據(jù)割疾。
增量數(shù)據(jù):在該次部署后嚎卫,數(shù)據(jù)庫(kù)表test_tb
的新產(chǎn)生的數(shù)據(jù),我們稱(chēng)之為增量數(shù)據(jù)杈曲。
然后遷移流程如下
(1)先計(jì)算你要遷移的那張表的max(主鍵)
驰凛。在遷移過(guò)程中,只遷移db-old
中test_tb
表里担扑,主鍵小等于該max(主鍵)
的值恰响,也就是所謂的歷史數(shù)據(jù)。
這里有特殊情況涌献,如果你的表用的是uuid胚宦,沒(méi)法求出max(主鍵)
,那就以創(chuàng)建時(shí)間作為劃分歷史數(shù)據(jù)和增量數(shù)據(jù)的依據(jù)燕垃。如果你的表用的是uuid,又沒(méi)有創(chuàng)建時(shí)間這個(gè)字段枢劝,我相信機(jī)智的你,一定有辦法區(qū)分出歷史數(shù)據(jù)和增量數(shù)據(jù)卜壕。
(2)在代碼中您旁,與test_tb
有關(guān)的業(yè)務(wù),多加一條往消息隊(duì)列中發(fā)消息的代碼轴捎,將操作的sql發(fā)送到消息隊(duì)列中鹤盒,至于消息體如何組裝蚕脏,大家自行考慮。需要注意的是侦锯,只發(fā)寫(xiě)請(qǐng)求的sql驼鞭,只發(fā)寫(xiě)請(qǐng)求的sql,只發(fā)寫(xiě)請(qǐng)求的sql尺碰。重要的事情說(shuō)三遍挣棕!
原因有二:
(1)只有寫(xiě)請(qǐng)求的sql對(duì)恢復(fù)數(shù)據(jù)才有用。
(2)系統(tǒng)中亲桥,絕大部分的業(yè)務(wù)需求是讀請(qǐng)求洛心,寫(xiě)請(qǐng)求比較少。
注意了题篷,在這個(gè)階段皂甘,我們不消費(fèi)消息隊(duì)列里的數(shù)據(jù)。我們只發(fā)寫(xiě)請(qǐng)求悼凑,消息隊(duì)列的消息堆積情況不會(huì)太嚴(yán)重偿枕!
(3)系統(tǒng)上線。另外户辫,寫(xiě)一段遷移程序渐夸,遷移db-old
中test_tb
表里,主鍵小于該max(主鍵)
的數(shù)據(jù)渔欢,也就是所謂的歷史數(shù)據(jù)墓塌。
上面步驟(1)~步驟(3)的過(guò)程如下
等到
db-old
中的歷史數(shù)據(jù)遷移完畢,則開(kāi)始遷移增量數(shù)據(jù)奥额,也就是在消息隊(duì)列里的數(shù)據(jù)苫幢。
(4)將遷移程序下線,寫(xiě)一段訂閱程序訂閱消息隊(duì)列中的數(shù)據(jù)
(5)訂閱程序?qū)⒂嗛喌降綌?shù)據(jù)垫挨,通過(guò)中間件寫(xiě)入新庫(kù)
(6)新老庫(kù)一致性驗(yàn)證韩肝,去除代碼中的雙寫(xiě)代碼,將涉及到
test_tb
表的讀寫(xiě)操作九榔,指向新庫(kù)哀峻。
上面步驟(4)~步驟(6)的過(guò)程如下
這里大家可能會(huì)有一個(gè)問(wèn)題,在步驟(1)~步驟(3),系統(tǒng)對(duì)歷史數(shù)據(jù)進(jìn)行操作哲泊,會(huì)造成不一致的問(wèn)題么剩蟀?
OK,不會(huì)切威。這里我們對(duì)delete
操作和update
操作做分析育特,因?yàn)橹挥羞@兩個(gè)操作才會(huì)造成歷史數(shù)據(jù)變動(dòng),insert
進(jìn)去的數(shù)據(jù)都是屬于增量數(shù)據(jù)先朦。
(1)對(duì)db-old
中test_tb
表的歷史數(shù)據(jù)發(fā)出delete
操作缰冤,數(shù)據(jù)還未刪除槽袄,就被遷移程序給遷走了。此時(shí)delete
操作在消息隊(duì)列里還有記錄锋谐,后期訂閱程序訂閱到該delete
操作,可以進(jìn)行刪除截酷。
(2)對(duì)db-old
中test_tb
表的歷史數(shù)據(jù)發(fā)出delete
操作涮拗,數(shù)據(jù)已經(jīng)刪除,遷移程序遷不走該行數(shù)據(jù)迂苛。此時(shí)delete
操作在消息隊(duì)列里還有記錄三热,后期訂閱程序訂閱到該delete
操作,再執(zhí)行一次delete
三幻,并不會(huì)對(duì)一致性有影響就漾。
對(duì)update
的操作類(lèi)似,不贅述念搬。
雙寫(xiě)部署法(二)
上面的方法有一個(gè)硬傷抑堡,注意我有一句話
(2)在代碼中,與test_tb有關(guān)的業(yè)務(wù)朗徊,多加一條往消息隊(duì)列中發(fā)消息的代碼首妖,將操作的sql發(fā)送到消息隊(duì)列中,至于消息體如何組裝爷恳,大家自行考慮有缆。
大家想一下,這么做温亲,是不是造成了嚴(yán)重的代碼入侵棚壁。將非業(yè)務(wù)代碼嵌入業(yè)務(wù)代碼,這么做栈虚,后期刪代碼的時(shí)候特別累袖外。
有沒(méi)什么方法,可以避免這個(gè)問(wèn)題的?
有的魂务,訂閱binlog
日志在刺。關(guān)于binlog
日志,我盡量下周寫(xiě)一篇《研發(fā)應(yīng)該掌握的binlog知識(shí)》头镊,這邊我就介紹一下作用
記錄所有數(shù)據(jù)庫(kù)表結(jié)構(gòu)變更(例如CREATE蚣驼、ALTER TABLE…)以及表數(shù)據(jù)修改(INSERT、UPDATE相艇、DELETE…)的二進(jìn)制日志颖杏。binlog不會(huì)記錄SELECT和SHOW這類(lèi)操作,因?yàn)檫@類(lèi)操作對(duì)據(jù)本身并沒(méi)有修改坛芽。
還記得我們?cè)?strong>雙寫(xiě)部署法(一)里介紹的留储,往消息隊(duì)列里發(fā)的消息翼抠,都是寫(xiě)操作的消息。而binlog
日志記錄的也是寫(xiě)操作获讳。所以訂閱該日志阴颖,也能滿足我們的需求。
于是步驟如下
(1)打開(kāi)binlog日志丐膝,系統(tǒng)正常上線就好
(2)還是寫(xiě)一個(gè)遷移程序量愧,遷移歷史數(shù)據(jù)。步驟和上面類(lèi)似帅矗,不啰嗦了偎肃。
步驟(1)~步驟(2)流程圖如下
(3)寫(xiě)一個(gè)訂閱程序,訂閱binlog(mysql中有canal)浑此。然后將訂閱到的數(shù)據(jù)通過(guò)中間件累颂,寫(xiě)入新庫(kù)。
(4)檢驗(yàn)一致性凛俱,沒(méi)問(wèn)題就切庫(kù)紊馏。
步驟(3)~步驟(4)流程圖如下