<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
為什麼備庫執行了 binlog 就可以跟主庫保持一致了呢?今天正式地和你介紹一下它。
在最開始,MySQL 是以容易學習和方便的高可用架構,被開發人員青睞的。而它的幾乎所有的高可用架構,都直接依賴於 binlog。雖然這些高可用架構已經呈現出越來越複雜的趨勢,但都是從最基本的一主一備演化過來的。
MySQL 主備的基本原理
圖 1 MySQL 主備切換流程
在狀態 1 中,使用者端的讀寫都直接存取節點 A,而節點 B 是 A 的備庫,只是將 A 的更新都同步過來,到本地執行。這樣可以保持節點 B 和 A 的資料是相同的。
當需要切換的時候,就切成狀態 2。這時候使用者端讀寫存取的都是節點 B,而節點 A 是 B 的備庫。
在狀態 1 中,雖然節點 B 沒有被直接存取,但是我依然建議你把節點 B(也就是備庫)設定成唯讀(readonly)模式。這樣做,有以下幾個考慮:
- 有時候一些運營類的查詢語句會被放到備庫上去查,設定為唯讀可以防止誤操作;
- 防止切換邏輯有 bug,比如切換過程中出現雙寫,造成主備不一致;
- 可以用 readonly 狀態,來判斷節點的角色。
你可能會問,我把備庫設定成唯讀了,還怎麼跟主庫保持同步更新呢?
這個問題,你不用擔心。因為 readonly 設定對超級 (super) 許可權使用者是無效的,而用於同步更新的執行緒,就擁有超級許可權。
接下來,我們再看看節點 A 到 B 這條線的內部流程是什麼樣的。圖 2 中畫出的就是一個 update 語句在節點 A 執行,然後同步到節點 B 的完整流程圖。
圖 2 主備流程圖
圖 2 中,包含了在上一篇文章中講到的 binlog 和 redo log 的寫入機制相關的內容,可以看到:主庫接收到使用者端的更新請求後,執行內部事務的更新邏輯,同時寫 binlog。
備庫 B 跟主庫 A 之間維持了一個長連線。主庫 A 內部有一個執行緒,專門用於服務備庫 B 的這個長連線。一個事務紀錄檔同步的完整過程是這樣的:
binlog 有兩種格式,一種是 statement,一種是 row。可能你在其他資料上還會看到有第三種格式,叫作 mixed,其實它就是前兩種格式的混合。
為了便於描述 binlog 的這三種格式間的區別,建立了一個表,並初始化幾行資料。
mysql> CREATE TABLE `t` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `a` (`a`), KEY `t_modified`(`t_modified`) ) ENGINE=InnoDB; insert into t values(1,1,'2018-11-13'); insert into t values(2,2,'2018-11-12'); insert into t values(3,3,'2018-11-11'); insert into t values(4,4,'2018-11-10'); insert into t values(5,5,'2018-11-09');
如果要在表中刪除一行資料的話,我們來看看這個 delete 語句的 binlog 是怎麼記錄的。
下面這個語句包含註釋,如果你用 MySQL 使用者端來做這個實驗的話,要記得加 -c 引數,否則使用者端會自動去掉註釋。
mysql> delete from t /*comment*/ where a>=4 and t_modified<='2018-11-10' limit 1;
當 binlog_format=statement 時,binlog 裡面記錄的就是 SQL 語句的原文。你可以用
mysql> show binlog events in 'master.000001';
命令看 binlog 中的內容。
圖 3 statement 格式 binlog 範例
為了說明 statement 和 row 格式的區別,我們來看一下這條 delete 命令的執行效果圖:
圖 4 delete 執行 warnings
執行這條 delete 命令產生了一個 warning,原因是當前 binlog 設定的是 statement 格式,並且語句中有 limit,所以這個命令可能是 unsafe 的。
這是因為 delete 帶 limit,很可能會出現主備資料不一致的情況。比如上面這個例子:
由於 statement 格式下,記錄到 binlog 裡的是語句原文,因此可能會出現這樣一種情況:在主庫執行這條 SQL 語句的時候,用的是索引 a;而在備庫執行這條 SQL 語句的時候,卻使用了索引 t_modified。因此,MySQL 認為這樣寫是有風險的。
那麼,如果我把 binlog 的格式改為 binlog_format=‘row’, 是不是就沒有這個問題了呢?
圖 5 row 格式 binlog 範例
與 statement 格式的 binlog 相比,前後的 BEGIN 和 COMMIT 是一樣的。但是,row 格式的 binlog 裡沒有了 SQL 語句的原文,而是替換成了兩個 event:Table_map 和 Delete_rows。
其實,我們通過圖 5 是看不到詳細資訊的,還需要藉助 mysqlbinlog 工具,用下面這個命令解析和檢視 binlog 中的內容。因為圖 5 中的資訊顯示,這個事務的 binlog 是從 8900 這個位置開始的,所以可以用 start-position 引數來指定從這個位置的紀錄檔開始解析。
mysqlbinlog -vv data/master.000001 --start-position=8900;
圖 6 row 格式 binlog 範例的詳細資訊
從這個圖中,我們可以看到以下幾個資訊:
當 binlog_format 使用 row 格式的時候,binlog 裡面記錄了真實刪除行的主鍵 id,這樣 binlog 傳到備庫去的時候,就肯定會刪除 id=4 的行,不會有主備刪除不同行的問題。
基於上面的資訊,我們來討論一個問題:為什麼會有 mixed 這種 binlog 格式的存在場景?推論過程是這樣的:
也就是說,mixed 格式可以利用 statment 格式的優點,同時又避免了資料不一致的風險。
因此,如果你的線上 MySQL 設定的 binlog 格式是 statement 的話,那基本上就可以認為這是一個不合理的設定。你至少應該把 binlog 的格式設定為 mixed。
現在越來越多的場景要求把 MySQL 的 binlog 格式設定成 row。這麼做的理由有很多,我來給你舉一個可以直接看出來的好處:恢復資料。
接下來,我們就分別從 delete、insert 和 update 這三種 SQL 語句的角度,來看看資料恢復的問題。
通過圖 6 你可以看出來,即使我執行的是 delete 語句,row 格式的 binlog 也會把被刪掉的行的整行資訊儲存起來。所以,如果你在執行完一條 delete 語句以後,發現刪錯資料了,可以直接把 binlog 中記錄的 delete 語句轉成 insert,把被錯刪的資料插入回去就可以恢復了。
如果你是執行錯了 insert 語句呢?那就更直接了。row 格式下,insert 語句的 binlog 裡會記錄所有的欄位資訊,這些資訊可以用來精確定位剛剛被插入的那一行。這時,你直接把 insert 語句轉成 delete 語句,刪除掉這被誤插入的一行資料就可以了。
如果執行的是 update 語句的話,binlog 裡面會記錄修改前整行的資料和修改後的整行資料。所以,如果你誤執行了 update 語句的話,只需要把這個 event 前後的兩行資訊對調一下,再去資料庫裡面執行,就能恢復這個更新操作了。
其實,由 delete、insert 或者 update 語句導致的資料操作錯誤,需要恢復到操作之前狀態的情況,也時有發生。MariaDB 的Flashback工具就是基於上面介紹的原理來回滾資料的。
雖然 mixed 格式的 binlog 現在已經用得不多了,但這裡我還是要再借用一下 mixed 格式來說明一個問題,來看一下這條 SQL 語句:
mysql> insert into t values(10,10, now());
如果我們把 binlog 格式設定為 mixed,你覺得 MySQL 會把它記錄為 row 格式還是 statement 格式呢?
先不要著急說結果,我們一起來看一下這條語句執行的效果。
圖 7 mixed 格式和 now()
可以看到,MySQL 用的居然是 statement 格式。你一定會奇怪,如果這個 binlog 過了 1 分鐘才傳給備庫的話,那主備的資料不就不一致了嗎?
接下來,我們再用 mysqlbinlog 工具來看看:
圖 8 TIMESTAMP 命令
從圖中的結果可以看到,原來 binlog 在記錄 event 的時候,多記了一條命令:SET TIMESTAMP=1546103491。它用 SET TIMESTAMP 命令約定了接下來的 now() 函數的返回時間。
因此,不論這個 binlog 是 1 分鐘之後被備庫執行,還是 3 天后用來恢復這個庫的備份,這個 insert 語句插入的行,值都是固定的。也就是說,通過這條 SET TIMESTAMP 命令,MySQL 就確保了主備資料的一致性。我之前看過有人在重放 binlog 資料的
之前看過有人在重放 binlog 資料的時候,是這麼做的:用 mysqlbinlog 解析出紀錄檔,然後把裡面的 statement 語句直接拷貝出來執行。你現在知道了,這個方法是有風險的。因為有些語句的執行結果是依賴於上下文命令的,直接執行的結果很可能是錯誤的。
所以,用 binlog 來恢復資料的標準做法是,用 mysqlbinlog 工具解析出來,然後把解析結果整個發給 MySQL 執行。類似下面的命令
mysqlbinlog master.000001 --start-position=2738 --stop-position=2973 | mysql -h127.0.0.1 -P13000 -u$user -p$pwd;
我們可以認為正常情況下主備的資料是一致的。也就是說,圖 1 中 A、B 兩個節點的內容是一致的。其實,圖 1 中的是 M-S 結構,但實際生產上使用比較多的是雙 M 結構,也就是圖 9 所示的主備切換流程。
圖 9 MySQL 主備切換流程 -- 雙 M 結構
對比圖 9 和圖 1,你可以發現,雙 M 結構和 M-S 結構,其實區別只是多了一條線,即:節點 A 和 B 之間總是互為主備關係。這樣在切換的時候就不用再修改主備關係。
但是,雙 M 結構還有一個問題需要解決。
業務邏輯在節點 A 上更新了一條語句,然後再把生成的 binlog 發給節點 B,節點 B 執行完這條更新語句後也會生成 binlog。(我建議你把引數 log_slave_updates 設定為 on,表示備庫執行 relay log 後生成 binlog)
那麼,如果節點 A 同時是節點 B 的備庫,相當於又把節點 B 新生成的 binlog 拿過來執行了一次,然後節點 A 和 B 間,會不斷地迴圈執行這個更新語句,也就是迴圈複製了。這個要怎麼解決呢?
從上面的圖 6 中可以看到,MySQL 在 binlog 中記錄了這個命令第一次執行時所在範例的 server id。因此,我們可以用下面的邏輯,來解決兩個節點間的迴圈複製的問題:
按照這個邏輯,如果我們設定了雙 M 結構,紀錄檔的執行流就會變成這樣:
binlog 在 MySQL 的各種高可用方案上扮演了重要角色。今天介紹的可以說是所有 MySQL 高可用方案的基礎。在這之上演化出了諸如多節點、半同步、MySQL group replication 等相對複雜的方案。
思考題: 說到迴圈複製問題的時候,我們說 MySQL 通過判斷 server id 的方式,斷掉死迴圈。但是,這個機制其實並不完備,在某些場景下,還是有可能出現死迴圈?又應該怎麼解決呢?
答案:一種場景是,在一個主庫更新事務後,用命令 set global server_id=x 修改了 server_id。等紀錄檔再傳回來的時候,發現 server_id 跟自己的 server_id 不同,就只能執行了。
另一種場景是,有三個節點的時候,如圖 7 所示,trx1 是在節點 B 執行的,因此 binlog 上的 server_id 就是 B,binlog 傳給節點 A,然後 A 和 A’搭建了雙 M 結構,就會出現迴圈複製。
到此這篇關於淺談如何保證Mysql主從一致的文章就介紹到這了,更多相關Mysql 主從一致內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45