1. 程式人生 > >面試官:"談談分庫分表吧?"

面試官:"談談分庫分表吧?"

 

 

面試官:“有併發的經驗沒?” 

應聘者:“有一點。”  

面試官:“那你們為了處理併發,做了哪些優化?”  

應聘者:“前後端分離啊,限流啊,分庫分表啊。。”  

面試官:"談談分庫分表吧?"  

應聘者:“bala。bala。bala。。”  

1、分庫分表的原因

1、隨著單庫中的資料量越來越大,相應的,查詢所需要的時間也越來越多,而面對MySQL這樣的資料庫,在進行新增一列這樣的操作時會有鎖表的操作,期間所有的讀寫操作都要等待,這個時候,相當於資料的處理遇到了瓶頸
2、單庫發生意外的時候,需要修復的是所有的資料,而多庫中的一個庫發生意外的時候,只需要修復一個庫(當然,也可以用物理分割槽的方式處理這種問題)

 

2、分庫分表的常用策略

2.1 垂直切分:

根據業務的不同,將原先擁有很多欄位的表拆分為兩個或者多個表,這樣的代價我個人覺得很大,原來對這應這個表的關係,開始細分,需要一定的重構,而且隨著資料量的增多,極有可能還要增加水平切分;

 

2.2 水平切分:

資料表結構,將資料分散在多個表中;

 

1.有瑕疵的簡單分庫分表(按id的大小分庫分表)

按照分片鍵(我們這裡就用id表示了)的大小來進行分庫分表,如果你的id是自增的,而且能保證在進行分庫分表後也是自增的,那麼能進行很好的改造,以id大小水平切分,而且極有可能不用遷移資料。

當然,這裡只列舉了比較小的資料量,實際情況的分庫的界限還是要依據具體的情況而定。這樣的分庫分表,因為新的資料總在一個庫裡,很可能導致熱點過於集中(讀寫可能集中在一個庫中),這是採取這種方式需要考慮的事情。
如果無法保證你的id是自增長的,那麼你的資料就會凌亂的分散在各個資料庫,這樣熱點確實就分散了,可是每當你增加一個數據庫的時候,你就有可能進行大量的資料遷移,應對這種情況,就是儘量減少資料遷移的代價,所以這裡運用一致性hash

的方式進行分庫分表比較好,可以儘可能的減少資料遷移,並且也能讓解決熱點過於集中的問題。一致性hash的分庫策略去百度一下或者谷歌一下應該很容易搜到。
這裡按id的大小來分庫,還可以發散到按照時間來分庫,比如說一個月的資料放在一個庫,這個使用mycat比較容易實現按時間分庫,不過你需要思考的資料的離散性,資料集中於一個兩月,而剩下的幾個月資料稀疏,這樣的又可能需要按照資料的生產規律合併幾個月到一個庫中,使得資料分佈均勻。

 

2.比較方便的取模分庫

一般的取模分庫分表是就是將id mod n,然後放入資料庫中,這樣能夠使資料分散,不會有熱點的問題,那麼,剩下的是,在擴容的時候,是否會有資料遷移的問題,一般的擴容,當然是會有資料遷移的。

取模.PNG


例子中,對3取模,當需要擴容的時候(假設增加兩個庫),則對5取模,這樣的結果必然是要進行資料遷移的,但是可以運用一些方法,讓它不進行資料遷移,scale-out擴充套件方案能夠避免在取模擴容的時候進行資料遷移。

 

(1)第一種擴容的方式:根據表的資料增加庫的數量

首先,我們有一個數據庫——DB_0,四張表——tb_0,tb_1,tb_2,tb_3
那麼我們現在資料到資料庫是這樣的:
DB="DB_0"
TB=“tb_"+id%4

 

 

當資料增加,需要進行擴容的時候,我增加一個數據庫DB_1
DB="DB_"+((id%4)/2)
TB=“tb_"+id%4

 


當我們的資料繼續飆升,這個時候又需要我們增加庫,這個時候進行加庫操作的時候,就不是增加一個庫,而必須是兩個,這樣才能保證不進行資料遷移。
DB="DB_"+id%4
TB=“tb_"+id%4


這個時候到了這個方案的加庫上限,不能繼續加庫了,否則就要進行資料遷移,所以這個方案的弊端還是挺大了,這樣的方式,也應該會造成單表的資料量挺大的。

 

(2)第二種擴容的方式:成倍的增加表

首先,我們還是一個數據庫——DB_0,兩張表——tb_0,tb_1
那麼我們現在資料到資料庫是這樣的:
DB="DB_0"
TB=“tb_"+id%2

 

 

假設當我們資料量打到一千萬的時候,我們增加一個庫,這時需要我們增加兩張表tb_0_1,tb_1_1,並且原來的DB_0中庫的表tb_1整表遷移到DB_1中,tb_0和tb_0_1放在DB_0中,tb_1和tb_1_1放到DB1中。
DB="DB_"+id%2
tb:
if(id<1千萬)    {  return  "tb_" + id %  2 }
else if(id>=1千萬)   {   return "tb_"+ id % 2 + "_1" }

 

資料的增長不可能到此為止,當增加到兩千萬的時候,我們需要加庫,這個時候,按照這種做法,我們需要增加兩個庫(DB_2,DB_3)和四張表(tb_0_2,tb_1_2,tb_2_2,tb_3_2),將上次新增的表整表分別放進兩個新的庫中,然後每個庫裡再生成一張新表。
DB:
if(id < 1千萬)    {  return  "DB_" + id %  2 }
else if(1千萬 <= id < 2千萬)   {   return  "DB_"+ id % 2 +2 }
else if(2千萬 <= id )   {   return  "DB_"+ id % 4 }
tb:
if(id < 1千萬)    {  return  "tb_" + id %  2 }
else if(1千萬 <= id < 2千萬)   {   return "tb_"+ id % 2 +"1" }
else if(id >= 2千萬) { return "tb
"+ id % 4+"_2" }

 

值得注意的一點,在id超出範圍的時候,該給怎麼樣的提示是值得思考的。

 

3、常用的分庫分表中介軟體

3.1 簡單易用的元件:

  • 噹噹sharding-jdbc

  • 蘑菇街TSharding

3.2 強悍重量級的中介軟體:

  • sharding

  • TDDL Smart Client的方式(淘寶)

  • Atlas(Qihoo 360)

  • alibaba.cobar(是阿里巴巴(B2B)部門開發)

  • MyCAT(基於阿里開源的Cobar產品而研發)

  • Oceanus(58同城資料庫中介軟體)

  • OneProxy(支付寶首席架構師樓方鑫開發)

  • vitess(谷歌開發的資料庫中介軟體)

4、分庫分表需要解決的問題

1、事務問題

解決事務問題目前有兩種可行的方案:分散式事務和通過應用程式與資料庫共同控制實現事務下面對兩套方案進行一個簡單的對比。

方案一:使用分散式事務
  • 優點: 交由資料庫管理,簡單有效

  • 缺點:效能代價高,特別是shard越來越多時

方案二:由應用程式和資料庫共同控制
  • 原理:將一個跨多個數據庫的分散式事務分拆成多個僅處 於單個數據庫上面的小事務,並通過應用程式來總控 各個小事務。

  • 優點:效能上有優勢

  • 缺點:需要應用程式在事務控制上做靈活設計。如果使用 了spring的事務管理,改動起來會面臨一定的困難。

2、跨節點Join的問題

只要是進行切分,跨節點Join的問題是不可避免的。但是良好的設計和切分卻可以減少此類情況的發生。解決這一問題的普遍做法是分兩次查詢實現。在第一次查詢的結果集中找出關聯資料的id,根據這些id發起第二次請求得到關聯資料。

3、跨節點的count,order by,group by以及聚合函式問題

這些是一類問題,因為它們都需要基於全部資料集合進行計算。多數的代理都不會自動處理合並工作。解決方案:與解決跨節點join問題的類似,分別在各個節點上得到結果後在應用程式端進行合併。和join不同的是每個結點的查詢可以並行執行,因此很多時候它的速度要比單一大表快很多。但如果結果集很大,對應用程式記憶體的消耗是一個問題。

4、資料遷移,容量規劃,擴容等問題

來自淘寶綜合業務平臺團隊,它利用對2的倍數取餘具有向前相容的特性(如對4取餘得1的數對2取餘也是1)來分配資料,避免了行級別的資料遷移,但是依然需要進行表級別的遷移,同時對擴容規模和分表數量都有限制。總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點,這也從一個側面反映出了Sharding擴容的難度。

5、事務

5.1 分散式事務
  • 參考: 
    關於分散式事務、兩階段提交、一階段提交、Best Efforts 1PC模式和事務補償機制的研究

  • 優點
    基於兩階段提交,最大限度地保證了跨資料庫操作的“原子性”,是分散式系統下最嚴格的事務實現方式。
    實現簡單,工作量小。由於多數應用伺服器以及一些獨立的分散式事務協調器做了大量的封裝工作,使得專案中引入分散式事務的難度和工作量基本上可以忽略不計。

  • 缺點
    系統“水平”伸縮的死敵。基於兩階段提交的分散式事務在提交事務時需要在多個節點之間進行協調,最大限度地推後了提交事務的時間點,客觀上延長了事務的執行時間,這會導致事務在訪問共享資源時發生衝突和死鎖的概率增高,隨著資料庫節點的增多,這種趨勢會越來越嚴重,從而成為系統在資料庫層面上水平伸縮的"枷鎖", 這是很多Sharding系統不採用分散式事務的主要原因。


基於Best Efforts 1PC模式的事務


參考spring-data-neo4j的實現。鑑於Best Efforts 1PC模式的效能優勢,以及相對簡單的實現方式,它被大多數的sharding框架和專案採用

5.2 事務補償(冪等值)

對於那些對效能要求很高,但對一致性要求並不高的系統,往往並不苛求系統的實時一致性,只要在一個允許的時間週期內達到最終一致性即可,這使得事務補償機制成為一種可行的方案。事務補償機制最初被提出是在“長事務”的處理中,但是對於分散式系統確保一致性也有很好的參考意義。籠統地講,與事務在執行中發生錯誤後立即回滾的方式不同,事務補償是一種事後檢查並補救的措施,它只期望在一個容許時間週期內得到最終一致的結果就可以了。事務補償的實現與系統業務緊密相關,並沒有一種標準的處理方式。一些常見的實現方式有:對資料進行對帳檢查;基於日誌進行比對;定期同標準資料來源進行同步,等等。

6、ID問題

一旦資料庫被切分到多個物理結點上,我們將不能再依賴資料庫自身的主鍵生成機制。一方面,某個分割槽資料庫自生成的ID無法保證在全域性上是唯一的;另一方面,應用程式在插入資料之前需要先獲得ID,以便進行SQL路由.
一些常見的主鍵生成策略

6.1 UUID

使用UUID作主鍵是最簡單的方案,但是缺點也是非常明顯的。由於UUID非常的長,除佔用大量儲存空間外,最主要的問題是在索引上,在建立索引和基於索引進行查詢時都存在效能問題。

結合資料庫維護一個Sequence表

此方案的思路也很簡單,在資料庫中建立一個Sequence表,表的結構類似於:

1CREATE TABLE `SEQUENCE` (  
2    `table_name` varchar(18) NOT NULL,  
3    `nextid` bigint(20) NOT NULL,  
4    PRIMARY KEY (`table_name`)  
5) ENGINE=InnoDB

每當需要為某個表的新紀錄生成ID時就從Sequence表中取出對應表的nextid,並將nextid的值加1後更新到資料庫中以備下次使用。此方案也較簡單,但缺點同樣明顯:由於所有插入任何都需要訪問該表,該表很容易成為系統性能瓶頸,同時它也存在單點問題,一旦該表資料庫失效,整個應用程式將無法工作。有人提出使用Master-Slave進行主從同步,但這也只能解決單點問題,並不能解決讀寫比為1:1的訪問壓力問題。

6.2 Twitter的分散式自增ID演算法Snowflake

在分散式系統中,需要生成全域性UID的場合還是比較多的,twitter的snowflake解決了這種需求,實現也還是很簡單的,除去配置資訊,核心程式碼就是毫秒級時間41位 機器ID 10位 毫秒內序列12位。

  • 10---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
    在上面的字串中,第一位為未使用(實際上也可作為long的符號位),接下來的41位為毫秒級時間,然後5位datacenter標識位,5位機器ID(並不算識別符號,實際是為執行緒標識),然後12位該毫秒內的當前毫秒內的計數,加起來剛好64位,為一個Long型。

這樣的好處是:整體上按照時間自增排序,並且整個分散式系統內不會產生ID碰撞(由datacenter和機器ID作區分),並且效率較高,經測試,snowflake每秒能夠產生26萬ID左右,完全滿足需要。

7、跨分片的排序分頁

一般來講,分頁時需要按照指定欄位進行排序。當排序欄位就是分片欄位的時候,我們通過分片規則可以比較容易定位到指定的分片,而當排序欄位非分片欄位的時候,情況就會變得比較複雜了。為了最終結果的準確性,我們需要在不同的分片節點中將資料進行排序並返回,並將不同分片返回的結果集進行彙總和再次排序,最後再返回給使用者。如下圖所示:

上面圖中所描述的只是最簡單的一種情況(取第一頁資料),看起來對效能的影響並不大。但是,如果想取出第10頁資料,情況又將變得複雜很多,如下圖所示:

有些讀者可能並不太理解,為什麼不能像獲取第一頁資料那樣簡單處理(排序取出前10條再合併、排序)。其實並不難理解,因為各分片節點中的資料可能是隨機的,為了排序的準確性,必須把所有分片節點的前N頁資料都排序好後做合併,最後再進行整體的排序。很顯然,這樣的操作是比較消耗資源的,使用者越往後翻頁,系統性能將會越差。

那如何解決分庫情況下的分頁問題呢?有以下幾種辦法:

如果是在前臺應用提供分頁,則限定使用者只能看前面n頁,這個限制在業務上也是合理的,一般看後面的分頁意義不大(如果一定要看,可以要求使用者縮小範圍重新查詢)。

如果是後臺批處理任務要求分批獲取資料,則可以加大page size,比如每次獲取5000條記錄,有效減少分頁數(當然離線訪問一般走備庫,避免衝擊主庫)。

分庫設計時,一般還有配套大資料平臺彙總所有分庫的記錄,有些分頁查詢可以考慮走大資料平臺。

8、分庫策略

分庫維度確定後,如何把記錄分到各個庫裡呢?

8.1 兩種方式:
  • 根據數值範圍,比如使用者Id為1-9999的記錄分到第一個庫,10000-20000的分到第二個庫,以此類推。

  • 根據數值取模,比如使用者Id mod n,餘數為0的記錄放到第一個庫,餘數為1的放到第二個庫,以此類推。

優劣比較:

評價指標按照範圍分庫按照Mod分庫
庫數量前期數目比較小,可以隨使用者/業務按需增長前期即根據mode因子確定庫數量,數目一般比較大
訪問效能前期庫數量小,全庫查詢消耗資源少,單庫查詢效能略差前期庫數量大,全庫查詢消耗資源多,單庫查詢效能略好
調整庫數量比較容易,一般只需為新使用者增加庫,老庫拆分也隻影響單個庫困難,改變mod因子導致資料在所有庫之間遷移
資料熱點新舊使用者購物頻率有差異,有資料熱點問題新舊使用者均勻到分佈到各個庫,無熱點
實踐中,為了處理簡單,選擇mod分庫的比較多。同時二次分庫時,為了資料遷移方便,一般是按倍數增加,比如初始4個庫,二次分裂為8個,再16個。這樣對於某個庫的資料,一半資料移到新庫,剩餘不動,對比每次只增加一個庫,所有資料都要大規模變動。
補充下,mod分庫一般每個庫記錄數比較均勻,但也有些資料庫,存在超級Id,這些Id的記錄遠遠超過其他Id,比如在廣告場景下,某個大廣告主的廣告數可能佔總體很大比例。如果按照廣告主Id取模分庫,某些庫的記錄數會特別多,對於這些超級Id,需要提供單獨庫來儲存記錄。

9、分庫數量

分庫數量首先和單庫能處理的記錄數有關,一般來說,Mysql 單庫超過5000萬條記錄,Oracle單庫超過1億條記錄,DB壓力就很大(當然處理能力和欄位數量/訪問模式/記錄長度有進一步關係)。

在滿足上述前提下,如果分庫數量少,達不到分散儲存和減輕DB效能壓力的目的;如果分庫的數量多,好處是每個庫記錄少,單庫訪問效能好,但對於跨多個庫的訪問,應用程式需要訪問多個庫,如果是併發模式,要消耗寶貴的執行緒資源;如果是序列模式,執行時間會急劇增加。

最後分庫數量還直接影響硬體的投入,一般每個分庫跑在單獨物理機上,多一個庫意味多一臺裝置。所以具體分多少個庫,要綜合評估,一般初次分庫建議分4-8個庫。

10、路由透明

分庫從某種意義上來說,意味著DB schema改變了,必然影響應用,但這種改變和業務無關,所以要儘量保證分庫對應用程式碼透明,分庫邏輯儘量在資料訪問層處理。當然完全做到這一點很困難,具體哪些應該由DAL負責,哪些由應用負責,這裡有一些建議:

對於單庫訪問,比如查詢條件指定使用者Id,則該SQL只需訪問特定庫。此時應該由DAL層自動路由到特定庫,當庫二次分裂時,也只要修改mod 因子,應用程式碼不受影響。

對於簡單的多庫查詢,DAL負責彙總各個資料庫返回的記錄,此時仍對上層應用透明。

11、使用框架還是自主研發

目前市面上的分庫分表中介軟體相對較多,其中基於代理方式的有MySQL Proxy和Amoeba,基於Hibernate框架的是Hibernate Shards,基於jdbc的有當當sharding-jdbc,基於mybatis的類似maven外掛式的有蘑菇街的蘑菇街TSharding,通過重寫spring的ibatis template類是Cobar Client,這些框架各有各的優勢與短板,架構師可以在深入調研之後結合專案的實際情況進行選擇,但是總的來說,我個人對於框架的選擇是持謹慎態度的。一方面多數框架缺乏成功案例的驗證,其成熟性與穩定性值得懷疑。另一方面,一些從成功商業產品開源出框架(如阿里和淘寶的一些開源專案)是否適合你的專案是需要架構師深入調研分析的。當然,最終的選擇一定是基於專案特點、團隊狀況、技術門檻和學習成本等綜合因素考量確定的。

5、如何部署

停機部署法 

大致思路就是,掛一個公告,半夜停機升級,然後半夜把服務停了,跑資料遷移程式,進行資料遷移。

步驟如下:

(1)出一個公告,比如“今晚00:00~6:00進行停機維護,暫停服務”
(2)寫一個遷移程式,讀db-old資料庫,通過中介軟體寫入新庫db-new1db-new2,具體如下圖所示

(3)校驗遷移前後一致性,沒問題就切該部分業務到新庫。

順便科普一下,這個中介軟體。現在流行的分庫分表的中介軟體有兩種,一種是proxy形式的,例如mycat,是需要額外部署一臺伺服器的。還有一種是client形式的,例如噹噹出的Sharding-JDBC,就是一個jar包,使用起來十分輕便。我個人偏向Sharding-JDBC,這種方式,無需額外部署,無其他依賴,DBA也無需改變原有的運維方式。

評價:

大家不要覺得這種方法low,我其實一直覺得這種方法可靠性很強。而且我相信各位讀者所在的公司一定不是什麼很牛逼的網際網路公司,如果你們的產品凌晨1點的使用者活躍數還有超過1000的,你們握個爪!畢竟不是所有人都在什麼電商公司的,大部分產品半夜都沒啥流量。所以此方案,並非沒有可取之處。

但是此方案有一個缺點,累!不止身體累,心也累!你想想看,本來定六點結束,你五點把資料庫遷移好,但是不知怎麼滴,程式切新庫就是有點問題。於是,眼瞅著天就要亮了,趕緊把資料庫切回老庫。第二個晚上繼續這麼幹,簡直是身心俱疲。

ps:這裡教大家一些技巧啊,如果你真的沒做過分庫分表,又想吹一波,漲一下工資,建議答這個方案。因為這個方案比較low,low到沒什麼東西可以深挖的,所以答這個方案,比較靠譜。

你剛才剛好有提到分庫分表的相關問題,我們當時部署的時候,先停機。然後半夜遷移資料,然後第二天將流量切到新庫,這種方案太累,不知道貴公司有沒有什麼更好的方案?

那麼這種情況下,面試官會有兩種回答。第一種,面試官硬著頭皮隨便扯。第二種,面試官真的做過,據實回答。記住,面試官怎麼回答的不重要。重點的是,你這個問題出去,會給面試官一種錯覺:"這個小夥子真的做過分庫分表。"

如果你擔心進去了,真派你去做分庫分表怎麼辦?OK,不要怕。我賭你試用期碰不到這個活。因為能進行分庫分表,必定對業務非常熟。還在試用期的你,必定對業務不熟,如果領導給你這種活,我只能說他有一顆大心臟。

ok,指點到這裡。面試本來就是一場鬥智鬥勇的過程,扯遠了,回到我們的主題。

雙寫部署法(一)

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

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

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

然後遷移流程如下

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

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

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

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

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

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

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

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


等到db-old中的歷史資料遷移完畢,則開始遷移增量資料,也就是在訊息佇列裡的資料。
(4)將遷移程式下線,寫一段訂閱程式訂閱訊息佇列中的資料
(5)訂閱程式將訂閱到到資料,通過中介軟體寫入新庫
(6)新老庫一致性驗證,去除程式碼中的雙寫程式碼,將涉及到test_tb表的讀寫操作,指向新庫。
上面步驟(4)~步驟(6)的過程如下

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

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

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

(2)對db-oldtest_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條。以此類推,找出不一致的資料,進行記錄即可。

 

END