如何搭建雙 M 結構的主從備份?
關于 MySQL 主從搭建,松哥之前寫過好多篇文章了,還錄過一個視頻。不過之前的都是一主一從的結構,但是小伙伴們知道,我們在項目中,更常見一種結構是雙 M 結構,即兩個 MySQL 實例,每個 MySQL 實例互為主備,這樣在主節點突然斷電或者不可用的時候,slave 節點可以很快切換為 master,架構圖如下:
在這種結構中,兩個 MySQL 實例的地位是平等的,互為對方的主備,我們判斷誰是主機誰是從機的方式主要是看 readonly,誰是只讀的,那誰就是從機,所以這種情況下,主從切換也很方便,只要修改 readonly 屬性即可。
接下來我們就來搭建一個雙 M 的主從備份,看看和單純的 M-S 結構的有啥區別。
1. 準備工作
以下配置基于 Docker。
這里,我們首先準備兩臺機器:
- M1:10.3.50.27:33061
- M2:10.3.50.27:33062
1.1 M1 配置
M1 的配置就三個步驟,比較容易:
(1)授權給 M2 服務器
GRANT REPLICATION SLAVE ON *.* to 'rep1'@'10.3.50.27' identified by '123';
FLUSH PRIVILEGES;
這里表示配置 M2 登錄用戶名為 rep1,密碼為 123,并且必須從 10.3.50.27 這個地址登錄,登錄成功之后可以操作任意庫中的任意表。其中,如果不需要限制登錄地址,可以將 IP 地址更換為一個 % 。
注意,在 MySQL8 里邊,這塊有一些變化。MySQL8 中用戶創建和授權需要分開,不能像上面那樣一步到位,具體方式如下:
CREATE USER `rep1`@`10.3.50.27` IDENTIFIED WITH caching_sha2_password BY 'javaboy.COM';
GRANT Replication Slave ON *.* TO `rep1`@`10.3.50.27`;
(2)修改主庫配置文件
開啟 binlog ,并設置 server-id ,每次修改配置文件后都要重啟 MySQL 服務才會生效
開啟 binlog 主要是修改 MySQL 的配置文件 mysqld.cnf,該文件在容器的 /etc/mysql/mysql.conf.d 目錄下。
針對該配置文件,我們做如下修改:
[mysqld]
# 這個參數表示啟用 binlog 功能,并指定 binlog 的存儲目錄
log-bin=javaboy_logbin
# 設置 binlog_format 格式,注意不要使用 STATEMENT
binlog_format=ROW
# 設置一個 binlog 文件的最大字節
# 設置最大 100MB
max_binlog_size=104857600
# 設置了 binlog 文件的有效期(單位:天)
expire_logs_days = 7
# binlog 日志只記錄指定庫的更新(配置主從復制的時候會用到)
binlog-do-db=javaboy_db
# binlog 日志不記錄指定庫的更新(配置主從復制的時候會用到)
#binlog-ignore-db=javaboy_no_db
# 寫緩存多少次,刷一次磁盤,默認 0 表示這個操作由操作系統根據自身負載自行決定多久寫一次磁盤
# 1 表示每一條事務提交都會立即寫磁盤,n 則表示 n 個事務提交才會寫磁盤
sync_binlog=0
# 為當前服務取一個唯一的 id(MySQL5.7 開始需要)
server-id=1
各項配置的含義松哥已經在注視中說明了。截圖如下:
如下圖:
- log-bin:同步的日志路徑及文件名,一定注意這個目錄要是 MySQL 有權限寫入的(我這里是偷懶了,直接放在了下面那個datadir下面)。
- binlog-do-db:要同步的數據庫名,當從機連上主機后,只有這里配置的數據庫才會被同步,其他的不會被同步。
- server-id: MySQL 在主從環境下的唯一標志符,給個任意數字,注意不能和 M2 重復,因為將來 server-id 用于標志 binlog 是由哪個庫產生的,所以主從數據庫的 server-id 千萬不能一樣,不然可能導致主從數據庫 binlog 的循環復制問題。
- 注意 binlog_format 的值為 ROW,具體原因在之前的文章中松哥已經和大家聊過了,這里就不再贅述。
配置完成后重啟 MySQL 服務端:
docker restart mysql33061
(3)查看 M1 當前二進制日志名和偏移量
這個操作的目的是為了在 M2 啟動后,從這個點開始進行數據的恢復:
show master status;
至此,M1 配置完成。
1.2 M2 配置
M2 的配置和 M1 一模一樣,唯一不同的地方在于,M2 的 mysqld.cnf 這個文件中的 server-id=2,其他都一模一樣,我就不重復了。
配置完成后,相當于 M2 現在也是一個主機,我們在 M2 上也可以執行 show master status; 命令,結果如下:
1.3 主從配置
接下來配置 M1 和 M2 分別為對方的主機。
M1 配置
先來配置給 M1 配置吧,執行如下命令設置主機:
change master to master_host='10.3.50.77',master_port=33062,master_user='rep1',master_password='123',master_log_file='javaboy_logbin.000001',master_log_pos=154;
這里配置了主機地址、端口以及從機登錄主機的用戶名和密碼,注意最后兩個參數要和 M2 中的保持一致。
注意,由于 MySQL8 密碼插件的問題,這個問題同樣會給主從配置帶來問題,所以在 MySQL8 配置主從上,上面這行命令需要添加 get_master_public_key=1 ,完整命令如下:
change master to master_host='10.3.50.77',master_port=33062,master_user='rep1',master_password='123',master_log_file='javaboy_logbin.000001',master_log_pos=154,get_master_public_key=1;
(1) 啟動 slave 進程
start slave;
啟動之后查看從機狀態:
show slave status\G;
(2)查看 slave 的狀態
主要是下面兩項值都要為為 YES,則表示配置正確:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
至此,配置完成,主機創建庫,添加數據,從機會自動同步。
如果這兩個有一個不為 YES ,表示主從環境搭建失敗,此時可以閱讀日志,查看出錯的原因,再具體問題具體解決。
M2 配置
接下來再來配置 M2,M2 和 M1 的配置基本上是一致的,change master 中記得把地址和端口寫對:
change master to master_host='10.3.50.77',master_port=33061,master_user='rep1',master_password='123',master_log_file='javaboy_logbin.000001',master_log_pos=154;
配置完成后,現在 M1 和 M2 就互為主備了。
1.4 測試
測試分兩步:
- M1 中新建 javaboy_db 庫,庫中建 user 表,表中插入一條記錄,然后查看 M2 中是否將數據同步過來了。
- M2 中向 user 表中添加一條記錄,查看 M1 中是否有對應的值。
經過測試,我們發現沒問題,現在可以兩邊互相同步對方的數據了。
2. 誰主誰從
雖然是雙 M 結構,但是在實際應用中還是得分個主從,那么雙 M 該怎么分主從呢?
在生產環境中,我們一般會將備份節點設置為 read_only ,也就是只讀,防止有誤操作,當然不用擔心設置為 read_only 后 binlog 的寫入也被阻止,super 用戶依然擁有寫入權限。
設置全庫只讀的辦法也很簡單,首先我們執行如下 SQL 先看看對應變量的值:
show variables like 'read_only';
可以看到,默認情況下, read_only 是 OFF,即關閉狀態,我們先把它改為 ON,執行如下 SQL:
set global read_only=1;
1 表示 ON,0 表示 OFF,執行結果如下:
這個 read_only 對 super 用戶無效,所以設置完成后,接下來我們退出來這個會話,然后創建一個不包含 super 權限的用戶,用新用戶登錄,登錄成功之后,執行一個插入 SQL,結果如下:
可以看到,這個錯誤信息中說,現在的 MySQL 是只讀的(只能查詢),不能執行當前 SQL。
如此設置之后,在 master 發生異常需要主從切換的時候再將 slave 臨時頂替上來。為了更好的做到主從同步,binlog 的類型建議使用 row 模式。