關於MySQL主從復制的過濾,例如通過binlog-ignore-db、replicate-do-db、replicate-wild-do-table等。如果不好好研究過這些過濾選項就用的話,是有可能造成主從數據不一致問題的。本文將參考MySQL-5.5官方文檔並結合實驗,和各位一起探討下這里的各個設置。
以下內容參考5.5官方文檔
binlog_format的設置會導致一些復制執行上的差異。
格式有三種(STATEMENT,ROW,MIXED,5.5默認為STATEMENT)
當使用MIXED格式時,binlog絕大多數情況也是以STATEMENT格式記錄,只有在下列情況下才會切換到ROW格式:
1、 當時用UUID()函數時
2、 當一個或多個擁有AUTO_INCREMENT列的表被更新同時有‘trigger’或者‘stored function’被調用時
# MIXED對於‘trigger’和‘stored function’總是使用statement-based
3、 執行INSERT DELAYED時
4、 當視圖里的某一部分需要row-based復制(例如UUID())時,創建該視圖的語句被改為row-based
5、 使用用戶自定義函數(UDF)時
6、 當某語句被判定為row-based,並且執行它的session需要用到臨時表,則session下的所有子語句都將以ROW格式記錄
7、 當使用USER(),CURRENT_USER()或者 CURRENT_USER
8、 當語句引用了一個或多個system variables。
9、 當使用LOAD_FILE()
下面幾點要注意
1.所有DDL語句都是基於statements,不論binlog_format如何設置
2.復制雙方binlog_format需一致,否則復制無法進行
3.Binlog格式影響到以下‘復制過濾’配置的行為
--binlog-do-db --binlog-ignore-db=ljk #黑名單,這個庫的修改不記錄二進制日志。 該選項的行為取決於binlog格式 對於Statement-based logging:當use ljk后(即當前庫為ljk時),所有的語句不被記錄進binlog 當登陸mysql后不使用use或者use ljk之外的庫,執行update ljk.table 依然會記錄近binlog並復制[只對ljk庫生效] 對於Row-based format:告訴服務器不記錄任何ljk庫下表的更改,無論當前在哪個庫(即無論有無use語句,是否使用use ljk) |
--replicate-do-db = ljk #白名單,允許復制哪個庫 該選項的行為取決於binlog格式 對於Statement-based replication:只有主庫在use ljk 之后執行的語句才會被從庫復制,沒有用use語句或者use其他庫后執行的語句均不被復制 對於Row-based replication:只有ljk庫的更改會被復制(無論use哪個庫或者是否use) 無論是否use或use哪個庫,ljk庫之外的變更都不會被復制 --replicate-ignore-db |
總結:Statement-based跟當前use的庫有關,Row-based更直接,只關心指定的庫‘做或不做’。
還有以下兩種參數可‘過濾復制’
以下兩種選項只對表的更改有影響,庫的復制不受這些參數影響(但是類似ljk.%這種,也會對庫起作用)
--replicate-do-table 這兩個選項在我的實驗里跟描述不太一致,詳細見下文實驗結果 --replicate-ignore-table |
--replicate-wild-do-table = ljk.% >>>>嚴格限定復制 無論use ljk或use 其他庫或不use,對ljk庫的更新都能被復制,同時,其他任何庫在任何情況下均不會復制(包括建庫建表操作) --replicate-wild-ignore-table |
根據以上,綜合建議:對復制的過濾,采用replicate-wild-do-table/ replicate-wild-ignore-table,比較嚴格和明確
下面是實驗過程(MySQL-5.5.39)
一、 主庫添加“binlog-ignore-db = mysql”,從庫不加過濾
庫操作: 在kai數據庫執行建表操作: 對表內容修改: 1. 不 use mysql> create table mysql.ljk (id int,name varchar(15)); 從庫復制 2. Use 其他庫 mysql> drop table mysql.ljk; 從庫復制 |
總結:對於主庫使用binlog-ignore-db來說:只有在use db執行后才會生效
二、從庫添加“replicate-ignore-db = mysql”,主庫不加過濾
庫操作 在kai數據庫執行建表操作 對表內容修改: 對mysql庫進行更改 |
總結對於從庫設定replicate-ignore-db 來說,基本上只有在主庫使用use db時才會生效。
三、從庫添加“replicate-ignore-table = mysql.%”,主庫不加過濾
注:這條規則加完在任何庫下執行任何語句均復制;相反,在從庫添加replicate-do-table = mysql.%后,在任何庫下執行任何sql都不會被復制。不知道是不是bug 庫操作: 在kai數據庫執行建表操作 對表內容修改: 對mysql庫進行更改 |
總結:好像有bug,應該來說在use db后,並在對應的庫下創建表應該會忽略同步。
四、 從庫添加“replicate-wild-ignore-table = mysql.%”,主庫不加過濾
庫操作: 在kai數據庫執行建表操作 對表內容修改: 對mysql庫進行更改 |
總結:使用replicate-wild-ignore-table之后,所有對於mysql庫下的表級別的任何操作都被忽略同步
綜上參考官方文檔以及實驗,可得出結論:
對於每一個添加的‘復制過濾’配置,應從兩方面考慮:
1. 不用use語句引用庫,或者use xxx引用其他庫之后再執行sql(又分兩部分:對‘過濾的庫/表’ 或 ‘對其他庫/表’)會怎樣
2. use xxx引用‘過濾的庫/表’,再執行sql(也分兩部分:對‘過濾的庫/表’ 或 ‘對其他庫/表’)會怎樣
除replicate-wild-do-table=/replicate-wild-ignore-table=外,其他過濾規則會受到“binlog_format”以及“當前所在庫”的影響(即所謂的跨庫問題)
建議使用 replicate-wild-ignore-table=mysql.% 因為replicate-ignore-db 是通過use db來確定是否過濾的。 而wild-ignore是通過真實被修改的表進行過濾的,更為准確。 |
實驗也驗證了上文提到的“對復制的過濾,采用replicate-wild-do-table/ replicate-wild-ignore-table,比較嚴格和明確”