MYSQL 主從不一致的原因分析

蓝胖子的编程梦發表於2024-03-13

資料庫作為儲存資料的元件,資料的一致性一定是要保證的前提,今天給出兩個場景來分析資料不一致的原因。

binlog同步模式導致主從不一致

在MYSQL 中主庫向從庫同步資料是利用binlog記錄修改操作,然後將binlog傳遞給從庫進行復制,binlog的格式有3種,

row 在對update,delete,insert語句進行記錄時會進行修改的行資料進行記錄。row格式的壞處在於比較佔用空間,比如更新十萬行資料,那麼row格式將會把10萬資料記錄下來。

statement 只會將原始的sql語句記錄下來。但是這種格式可能會引起主備不一致。

mixed 是前面兩種格式的混合,MYSQL會自己去判斷這條sql是不是會造成主備不一致,將引起主備不一致的sql記錄成row格式。

statement 為什麼會主備不一致?

舉一個例子來說明下,statement主備不一致的原因,例如下面的sql

update navigation.t_account set id = uuid();

當你使用 類似uuid或者now這種動態函式時,那麼在主庫的生成結果將會和從庫不同。造成資料的主備不一致。

為什麼大多數時候我們還是用row

大多時候,我們還是用row 格式寫入binlog,這樣帶來的好處是便於恢復資料,下面我舉例說明下,

  • 當你執行錯delete語句,能夠透過binlog日誌找到刪除行的所有欄位資訊,不過需要注意的是,需要將binlog_row_image 引數設定為FULL,才會記錄所有欄位資訊,如果設定為MINIMAL 則只會記錄刪除欄位資訊。
  • 當你執行錯update語句,透過binlog記錄的修改前後的整行資料,對資料進行恢復。
  • 當你執行錯insert語句,能夠透過binlog找到插入資料的id,對錯誤插入的資料進行刪除。

所以,為了避免主從不一致,還是選用row 格式記錄binblog吧,或者至少還是選用mixed

主備切換導致主從不一致

第二種主從不一致的場景是發生在主備切換時,我先直接說下結論,主備切換方式其實分可靠性優先方式與可用性優先方式。

可靠性優先方式,MYSQL服務可能會存在短暫的不可提供服務的時間段,可用性優先則是保證MYSQL在切換過程中都是可用的。

為了方便,下面我將主主資料庫稱為master,從資料庫稱為slave。

可靠性優先方式

1,判斷slave是否已經 seconds_behind_master,是否小於5s或更短,seconds_behind_master 代表主從同步延遲的時間,如果小於5s,則繼續下一步。

2,修改master的readonly 引數為true, 將master變為只讀狀態。

3,判斷slave的主從同步延遲是否變為0,即seconds_behind_master 等於0,等於0後,繼續下一步。

4,修改 slave的 readonly引數改為false,將slave變為可讀可寫狀態。

5,將業務請求轉發到slave,原先master,修改為新master的從庫。

這個切換過程,資料庫是有一段時間不可寫的,必須等待slave主從延遲同步變為0以後才行,所以這也是為什麼要在seconds_behind_master 在一個較小的值才開始進行主備切換的原因。

可用性優先方式

接著看下保證可用性優先的主備切換方式,在上述主備切換步驟中,我們去掉第三個步驟,也就是不等到主從同步完成就去切換主備。

現在假設現在的binlog為 row格式。表定義為

mysql> CREATE TABLE `t` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `c` int(11) unsigned DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;

insert into t(c) values(1),(2),(3);

業務此時進行插入操作,

insert into t(c) values(4);
insert into t(c) values(5);

當在執行完第一個sql時,進行主備切換,且假設此時備庫並沒有完成第一條sql的同步。如下圖所示,在插入4這條資料時,將slave改為可寫,接著業務系統後續的寫就往slave寫入了5這條資料。注意此時master的4這條資料還沒有同步到slave。

image.png

接著開始準備更改主備關係,如下圖所示,更改關係前,有可能slave才會進行來自master的4這條資料的寫入,但是因為slave中已經有id為4的資料了,所以會導致插入失敗。

image.png
修改slave為master後,插入到之前從庫的(4,5)這條資料 會同步到新的slave主機(即舊master),但是這個時候也會因為舊master有id為4的這條資料導致同步失敗。主備同步就會自動停止。

可以看到,最後主從資料庫中有id等於4這條資料不一樣。

所以,可用性優先的主備切換方式是有可能導致主備不一致的。

資料庫最重要還是資料的正確性,拿許多業務場景來說,如果資料錯亂了,是較難恢復的,但是如果業務失敗了,還可以透過重試重新填充資料,怕就怕成功一半,失敗一半。所以主備切換的時候儘量還是可靠性優先方式比較好。

最後,

自薦一波✅:

歡迎朋友們關注我的公眾號📢📢:【藍胖子的程式設計夢】!

學習容器知識🐳,效能監控🚀,Golang🐋 相關程式設計知識

相關文章