mysql GTID主從複製故障後不停機恢復同步流程
GTID實現主從複製資料同步
GTID是一個基於原始mysql伺服器生成的一個已經被成功執行的全域性事務ID,它由伺服器ID以及事務ID組成,這個全域性事務ID不僅僅在原始伺服器上唯一,在所有主從關係的mysql伺服器上也是唯一的。正式因為這樣一個特性使得mysql主從複製變得更加簡單,以及資料庫一致性更可靠。
介紹
GTID的概念
- 全域性事務標識:global transaction identifiers
- GTID是一個事務一一對應,並且全域性唯一ID
- 一個GTID在一個伺服器上只執行一次,避免重複執行導致資料混亂不一致
- 不再使用傳統的MASTER_LOG_FILE+MASTER_LOG_POS開啟複製,而是採用MASTER_AUTO_POSTION=1的方式開啟複製。
- 從MYSQL-5.6.5及後續版本開始支援
GTID的組成
GTID = server_uuid:transaction_id
server_uuid:mysql伺服器的唯一標識,檢視方法mysql客戶端內:show variables like '%server_uuid%';
transaction_id:此id是當前伺服器中提交事務的一個序列號,從1開始自增長,一個數值對應一個事務
GTID號示例:c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-5
GTID的優勢
- 實現主從更簡單,不用像以前一樣尋找log_file和log_pos
- 比傳統的主從更加安全
- GTID是連續沒有空洞的,保證資料一致性,零丟失。
GTID工作原理
- master更新資料時,會在事務前產生GTID,一同記錄到binlog日誌中
- slave端的I/O執行緒將變更的binlog,寫入到本地的relay log中
- SQL執行緒從relay log中獲取GTID,然後對比slave端的binlog是否有記錄(所以MySQL5.6 slave端必須開啟binlog)
- 如果有記錄,說明該GTID的事務已經執行,slave會忽略
- 如果沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog
- 在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描
開始配置GTID複製
主:192.168.152.253 Centos7
從:192.168.152.252 Centos8
測試資料庫:vfan
測試表:student
1、修改mysql服務配置檔案,新增以下引數,隨後重啟:
server-id=100 #server id log-bin=/var/lib/mysql/mysql-bin #開啟binlog並指定儲存位置 expire_logs_days=10 #日誌儲存時間為10天 gtid_mode=on #gtid模組開關 enforce_gtid_consistency=on #啟動GTID強一致性,開啟gtid模組必須開啟此功能。 binlog_format=row #bin_log日誌格式,共有三種STATEMENT、ROW、MIXED;預設為STATEMENT skip_slave_start=1 #防止複製隨著mysql啟動而自動啟動
主伺服器和從伺服器的配置一致即可,server-id更改一下
2、在主伺服器中建立從伺服器連線的使用者
CREATE USER 'copy'@'192.168.152.252' IDENTIFIED BY 'copy'; GRANT REPLICATION SLAVE ON *.* TO 'copy'@'192.168.152.252'; flush privileges;
建立完畢記得要測試下slave機是否能登入成功
3、使用mysqldump使兩資料庫資料同步
主mysql執行: mysqldump -uroot -proot1 vfan > dump2.sql scp dump2.sql 192.168.152.252:/data/ 從mysql執行: mysql> source /data/dump2.sql
當前主、從伺服器資料內容一致,都是以下資料:
mysql> select * from student; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | Tony | 18 | | 2 | Any | 17 | | 3 | Goy | 20 | | 4 | Baly | 18 | | 5 | Heg | 19 | | 6 | hhh | 100 | | 7 | lll | 99 | +----+------+-----+ 7 rows in set (0.01 sec)
4、開啟主從複製
mysql> CHANGE MASTER TO MASTER_HOST='192.168.152.253',MASTER_USER='copy',MASTER_PASSWORD='copy',MASTER_PORT=3306,MASTER_AUTO_POSITION=1; Query OK, 0 rows affected, 2 warnings (0.04 sec) mysql> start slave; Query OK, 0 rows affected (0.01 sec) ## 檢視slave狀態 mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.152.253 Master_User: copy Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000014 Read_Master_Log_Pos: 897 Relay_Log_File: kubenode2-relay-bin.000002 Relay_Log_Pos: 416 Relay_Master_Log_File: mysql-bin.000014 Slave_IO_Running: Yes Slave_SQL_Running: Yes
5、檢查是否同步
主伺服器中插入資料: mysql> INSERT INTO student(name,age) VALUES('gogoo',50),('zhazha',25); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 從伺服器中讀取: mysql> select * from student; +----+--------+-----+ | id | name | age | +----+--------+-----+ | 1 | Tony | 18 | | 2 | Any | 17 | | 3 | Goy | 20 | | 4 | Baly | 18 | | 5 | Heg | 19 | | 6 | hhh | 100 | | 7 | lll | 99 | | 8 | gogoo | 50 | | 9 | zhazha | 25 | +----+--------+-----+ 9 rows in set (0.00 sec)
資料已經同步,基礎的主從複製已經搭建完成
現在模擬一個主從複製架構中,從伺服器中途複製失敗,不再同步主伺服器的場景,並要求不停業務進行資料同步修復,恢復一致。
1、首先先模擬一個數據插入的場景
vim insert.sh
#!/usr/bin/env bash values=(`find /usr/ -type d | awk -F '/' '{print $NF}' | sort -u`) while true do age=$(( $RANDOM%100 )) name=${values[$(( $RANDOM%6 ))]} mysql -h127.1 -P3306 -uroot -proot1 -e "INSERT INTO vfan.student(name,age) VALUES('"${name}"',${age});" &> /dev/null sleep $(( $RANDOM%5 )) done
執行指令碼,資料在隨機插入(插入時間間隔 < 5s)
目前主mysql資料:
mysql> select * from student; +----+---------------------+-----+ | id | name | age | ...... | 97 | _ | 2 | | 98 | 00bash | 15 | | 99 | 00bash | 52 | | 100 | 00bash | 43 | | 101 | _ | 65 | | 102 | 00 | 67 | +-----+---------------------+-----+ 102 rows in set (0.01 sec)
2、資料還在陸續插入,此時模擬slave節點宕機或異常(在此就直接stop slave;)
mysql> stop slave; Query OK, 0 rows affected (0.01 sec)
3、此時主庫資料還在增加,而從庫已經不同步,以下是從庫資料:
mysql> select * from student; +----+---------------------+-----+ | id | name | age | ...... | 82 | 00bash | 50 | | 83 | 00systemd-bootchart | 36 | | 84 | 00bash | 48 | | 85 | 00systemd-bootchart | 41 | | 86 | 00 | 72 | +----+---------------------+-----+ 86 rows in set (0.00 sec)
4、開始從庫恢復資料
思路:
先通過mysqldump全量備份當前的資料,由於不能影響業務,所以在mysqldump資料時不能造成鎖表。要保持資料寫入
由於mysqldump時資料還在寫入,所以有一部分資料還是會同步不全,所以匯入mysqldump的資料後,跳過dump中包含的GTID事務,再重新建立一次主從配置,開啟slave執行緒,恢復資料並同步。
(1)mysqldump不鎖表備份資料
mysqldump -uroot -proot1 --single-transaction --master-data=2 -R vfan | gzip > dump4.sql
主要起作用引數:--single-transaction
(2)檢視當前mysqldump匯出資料的GTID號
[root@TestCentos7 data]# grep GLOBAL.GTID_PURGED dump4.sql SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ 'c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-228';
以上的 c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-228 表示MASTER機執行到的GTID事務號
(3)去從資料庫匯入
scp dump4.sql 192.168.152.252:/data mysql客戶端內: mysql> source /data/dump4.sql 此時從庫資料: mysql> select * from student; | 230 | 00 | 53 | | 231 | 00bash | 66 | | 232 | _ | 18 | | 233 | 0.33.0 | 98 | | 234 | 00bash | 14 | +-----+---------------------+-----+ 234 rows in set (0.00 sec) 主庫資料: | 454 | _ | 46 | | 455 | 03modsign | 59 | | 456 | 00systemd-bootchart | 77 | | 457 | 03modsign | 6 | | 458 | 0.33.0 | 88 | +-----+---------------------+-----+ 458 rows in set (0.00 sec)
從庫資料恢復一部分到234行,主庫資料依然在增加,已經是458條
(4)由於我們mysqldump的資料已經包含了在MASTER執行的 1-228 個事務,所以我們在SLAVE進行同步的時候,要忽略這些事務不再進行同步,不然會出現類似於這種報錯:
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.152.253 Master_User: copy Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000002 Read_Master_Log_Pos: 137827 Relay_Log_File: kubenode2-relay-bin.000002 Relay_Log_Pos: 417 Relay_Master_Log_File: mysql-bin.000002 Slave_IO_Running: Yes Slave_SQL_Running: No Last_Errno: 1062 Last_Error: Could not execute Write_rows event on table vfan.student; Duplicate entry '87' for key 'student.PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000002, end_log_pos 10588
要想跳過某些GTID,SLAVE必須保證 gtid_purged 引數為空才能正確跳過,檢視當前的gtid_purged:
mysql> show global variables like '%gtid%'; +----------------------------------+-------------------------------------------------------------------------------------+ | Variable_name | Value | +----------------------------------+-------------------------------------------------------------------------------------+ | binlog_gtid_simple_recovery | ON | | enforce_gtid_consistency | ON | | gtid_executed | b30cb2ff-32d4-11eb-a447-000c292826bc:1-2, c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-80 | | gtid_executed_compression_period | 1000 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-70 | | session_track_gtids | OFF | +----------------------------------+-------------------------------------------------------------------------------------+ 8 rows in set (0.02 sec)
當前gtid_purged不為空,所以我們要先設定它為空,執行:
mysql> reset master; Query OK, 0 rows affected (0.05 sec) mysql> show global variables like '%gtid%'; +----------------------------------+-------+ | Variable_name | Value | +----------------------------------+-------+ | binlog_gtid_simple_recovery | ON | | enforce_gtid_consistency | ON | | gtid_executed | | | gtid_executed_compression_period | 1000 | | gtid_mode | ON | | gtid_owned | | | gtid_purged | | | session_track_gtids | OFF | +----------------------------------+-------+ 8 rows in set (0.00 sec)
(5)gtid_purged為空後,開始重置SLAVE
mysql> stop slave; Query OK, 0 rows affected (0.00 sec) mysql> reset slave all; Query OK, 0 rows affected (0.02 sec)
(6)重置後,設定跳過的GTID,並重新同步MASTER
mysql> SET @@GLOBAL.GTID_PURGED='c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-228'; Query OK, 0 rows affected (0.01 sec) mysql> CHANGE MASTER TO MASTER_HOST='192.168.152.253',MASTER_USER='copy',MASTER_PASSWORD='copy',MASTER_PORT=3306,MASTER_AUTO_POSITION=1; Query OK, 0 rows affected, 2 warnings (0.04 sec)
(7)開啟SLAVE程序,檢視同步狀態
mysql> start slave; Query OK, 0 rows affected (0.01 sec) mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.152.253 Master_User: copy Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000002 Read_Master_Log_Pos: 137827 Relay_Log_File: kubenode2-relay-bin.000002 Relay_Log_Pos: 84993 Relay_Master_Log_File: mysql-bin.000002 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 137827 Relay_Log_Space: 85206 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 100 Master_UUID: c9fba9e2-db3b-11eb-81d4-000c298d8da1 Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: c9fba9e2-db3b-11eb-81d4-000c298d8da1:229-519 Executed_Gtid_Set: c9fba9e2-db3b-11eb-81d4-000c298d8da1:1-519 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: Master_public_key_path: Get_master_public_key: 0 Network_Namespace: 1 row in set (0.00 sec)
可以看到,同步正常!
(8)最後,檢視master與slave資料是否一致
MASTER資料:SELECT * FROM student; | 520 | 00systemd-bootchart | 18 | | 521 | 00systemd-bootchart | 44 | | 522 | 03modsign | 98 | | 523 | 00systemd-bootchart | 45 | | 524 | 00 | 90 | | 525 | 03modsign | 21 | +-----+---------------------+-----+ 525 rows in set (0.00 sec) SLAVE資料:SELECT * FROM student; | 519 | 0.33.0 | 99 | | 520 | 00systemd-bootchart | 18 | | 521 | 00systemd-bootchart | 44 | | 522 | 03modsign | 98 | | 523 | 00systemd-bootchart | 45 | | 524 | 00 | 90 | | 525 | 03modsign | 21 | +-----+---------------------+-----+ 525 rows in set (0.00 sec)
在我們修過程中插入的資料也已經全部同步。資料完全一致,主從複製修復完成。