怎麼進行分庫分表以及資料遷移

2021-10-05 02:46:36 字數 3699 閱讀 4503

已經明白為啥要分庫分表了,你也知道常用的分庫分表中介軟體了,你也設計好你們如何分庫分表的方案了(水平拆分、垂直拆分、分表),那問題來了,你接下來該怎麼把你那個單庫單錶的系統給遷移到分庫分表上去?

友情提示

3個庫,每個庫里分了4個表,每個表要放50萬的資料量

假設你已經選擇了乙個分庫分表的資料庫中介軟體,sharding-jdbc,mycat,都可以

你怎麼把線上系統平滑地遷移到分庫分表上面去

sharding-jdbc:自己上官網,找乙個官網最基本的例子,自己寫一下,試一下,跑跑看,是非常簡單的

mycat:自己上官網,找乙個官網最基本的例子,自己寫一下,試一下看看

從low到高大上有好幾種方案,都給你說一下

接著到0點,停機,系統挺掉,沒有流量寫入了,此時老的單庫單錶資料庫靜止了。然後你之前得寫好乙個導數的一次***,此時直接跑起來,然後將單庫單錶的資料嘩嘩嘩讀出來,寫到分庫分表裡面去。

導數完了之後,就ok了,修改系統的資料庫連線配置啥的,包括可能**和sql也許有修改,那你就用最新的**,然後直接啟動連到新的分庫分表上去。

驗證一下,ok了,完美,大家伸個懶腰,看看看凌晨4點鐘的北京夜景,打個滴滴回家吧

但是這個方案比較low,誰都能幹,我們來看看高大上一點的方案

常用的一種遷移方案,比較靠譜一些,不用停機,不用看北京凌晨4點的風景

然後系統部署之後,新庫資料差太遠,用之前說的導數工具,跑起來讀老庫資料寫新庫,寫的時候要根據gmt_modified這類字段判斷這條資料最後修改的時間,除非是讀出來的資料在新庫里沒有,或者是比新庫的資料新才會寫。

接著導完一輪之後,有可能資料還是存在不一致,那麼就程式自動做一輪校驗,比對新老庫每個表的每條資料,接著如果有不一樣的,就針對那些不一樣的,從老庫讀資料再次寫。反覆迴圈,直到兩個庫每個表的資料都完全一致為止。

接著當資料完全一致了,就ok了,基於僅僅使用分庫分表的最新**,重新部署一次,不就僅僅基於分庫分表在操作了麼,還沒有幾個小時的停機時間,很穩。所以現在基本玩兒資料遷移之類的,都是這麼幹了。

雙寫部署法(一)

這個就是不停機部署法,這裡我需要先引進兩個概念:歷史資料和增量資料。

假設,我們是對一張叫做test_tb的表進行拆分,因為你要進行雙寫,系統裡頭和test_tb表有關的業務之前必定會加入一段雙寫**,同時往老庫和新庫中寫,然後進行部署,那麼

歷史資料:在該次部署前,資料庫表test_tb的有關資料,我們稱之為歷史資料。

增量資料:在該次部署後,資料庫表test_tb的新產生的資料,我們稱之為增量資料。

然後遷移流程如下

(1)先計算你要遷移的那張表的max(主鍵)。在遷移過程中,只遷移db-old中test_tb表裡,主鍵小等於該max(主鍵)的值,也就是所謂的歷史資料。

這裡有特殊情況,如果你的錶用的是uuid,沒法求出max(主鍵),那就以建立時間作為劃分歷史資料和增量資料的依據。如果你的錶用的是uuid,又沒有建立時間這個字段,我相信機智的你,一定有辦法區分出歷史資料和增量資料。

(2)在**中,與test_tb有關的業務,多加一條往訊息佇列中發訊息的**,將操作的sql傳送到訊息佇列中,至於訊息體如何組裝,大家自行考慮。需要注意的是,只發寫請求的sql,只發寫請求的sql,只發寫請求的sql。重要的事情說三遍!

原因有二:

(1)只有寫請求的sql對恢復資料才有用。

(2)系統中,絕大部分的業務需求是讀請求,寫請求比較少。

注意了,在這個階段,我們不消費訊息佇列裡的資料。我們只發寫請求,訊息佇列的訊息堆積情況不會太嚴重!

(3)系統上線。另外,寫一段遷移程式,遷移db-old中test_tb表裡,主鍵小於該max(主鍵)的資料,也就是所謂的歷史資料。

上面步驟(1)~步驟(3)的過程如下

等到db-old中的歷史資料遷移完畢,則開始遷移增量資料,也就是在訊息佇列裡的資料。

(4)將遷移程式下線,寫一段訂閱程式訂閱訊息佇列中的資料

(5)訂閱程式將訂閱到到資料,通過中介軟體寫入新庫

(6)新老庫一致性驗證,去除**中的雙寫**,將涉及到test_tb表的讀寫操作,指向新庫。

上面步驟(4)~步驟(6)的過程如下

這裡大家可能會有乙個問題,在步驟(1)~步驟(3),系統對歷史資料進行操作,會造成不一致的問題麼?

ok,不會。這裡我們對delete操作和update操作做分析,因為只有這兩個操作才會造成歷史資料變動,insert進去的資料都是屬於增量資料。

(1)對db-old中test_tb表的歷史資料發出delete操作,資料還未刪除,就被遷移程式給遷走了。此時delete操作在訊息佇列裡還有記錄,後期訂閱程式訂閱到該delete操作,可以進行刪除。

(2)對db-old中test_tb表的歷史資料發出delete操作,資料已經刪除,遷移程式遷不走該行資料。此時delete操作在訊息佇列裡還有記錄,後期訂閱程式訂閱到該delete操作,再執行一次delete,並不會對一致性有影響。

對update的操作類似,不贅述。

雙寫部署法(二)

上面的方法有乙個硬傷,注意我有一句話

(2)在**中,與test_tb有關的業務,多加一條往訊息佇列中發訊息的**,將操作的sql傳送到訊息佇列中,至於訊息體如何組裝,大家自行考慮。

大家想一下,這麼做,是不是造成了嚴重的**入侵。將非業務**嵌入業務**,這麼做,後期刪**的時候特別累。

有沒什麼方法,可以避免這個問題的?

有的,訂閱binlog日誌。關於binlog日誌,我盡量下週寫一篇《研發應該掌握的binlog知識》,這邊我就介紹一下作用

記錄所有資料庫表結構變更(例如create、alter table…)以及表資料修改(insert、update、delete…)的二進位制日誌。binlog不會記錄select和show這類操作,因為這類操作對據本身並沒有修改。

還記得我們在雙寫部署法(一)裡介紹的,往訊息佇列裡發的訊息,都是寫操作的訊息。而binlog日誌記錄的也是寫操作。所以訂閱該日誌,也能滿足我們的需求。

於是步驟如下

(1)開啟binlog日誌,系統正常上線就好

(2)還是寫乙個遷移程式,遷移歷史資料。步驟和上面類似,不囉嗦了。

步驟(1)~步驟(2)流程圖如下

(3)寫乙個訂閱程式,訂閱binlog(mysql中有canal。至於oracle中,大家就隨緣自己寫吧)。然後將訂閱到的資料通過中介軟體,寫入新庫。

(4)檢驗一致性,沒問題就切庫。

步驟(3)~步驟(4)流程圖如下

怎麼驗資料一致性

這裡大概介紹一下吧,這篇的篇幅太長了,大家心裡有底就行。

(1)先驗數量是否一致,因為驗數量比較快。

至於驗具體的字段,有兩種方法:

(2.1)有一種方法是,只驗關鍵性的幾個字段是否一致。

(2.2)還有一種是 ,一次取50條(不一定50條,具體自己定,我只是舉例),然後像拼字串一樣,拼在一起。用md5進行加密,得到一串數值。新庫一樣如法炮製,也得到一串數值,比較兩串數值是否一致。如果一致,繼續比較下50條資料。如果發現不一致,用二分法確定不一致的資料在0-25條,還是26條-50條。以此類推,找出不一致的資料,進行記錄即可。

MySQL 分表分庫怎麼進行資料切分

關係型資料庫本身比較容易成為系統瓶頸,單機儲存容量 連線數 處理能力都有限。當單錶的資料量達到1000w或100g以後,由於查詢維度較多,即使新增從庫 優化索引,做很多操作時效能仍下降嚴重。此時就要考慮對其進行切分了,切分的目的就在於減少資料庫的負擔,縮短查詢時間。資料庫分布式核心內容無非就是資料切...

MySQL分庫分表遷移方案

現在有乙個未分庫分表的系統,未來要分庫分表,如何設計才可以讓系統從未分庫分表動態切換到分庫分表上?你看看,你現在已經明白為啥要分庫分表了,你也知道常用的分庫分表中介軟體了,你也設計好你們如何分庫分表的方案了 水平拆分 垂直拆分 分表 那問題來了,你接下來該怎麼把你那個單庫單錶的系統給遷移到分庫分表上...

談談 分庫 分表 怎麼用

重中之重,什麼是分庫分表?什麼情況下用到分庫分表?其次為分庫分表的方式?怎麼用?二 資料分庫 三 注意點 什麼是?顧名思義,將乙個庫的資料分散到多個庫中,把乙個表的資料分到多個表中儲存。什麼情況下用到?當乙個庫被建立後,隨著時間和業務量的增加,或者業務流量本來就很多的情況下,資料庫中的資料會越來越多...