網上關于MySQL官方版本的GTID復制文章很多,我就不再贅述。我這里主要想寫一點關于MariaDB的GTID復制特性。相比官方mysql的GTID復制,MariaDB更加的方便好用。
參考文檔?https://mariadb.com/kb/en/mariadb/gtid/
MariaDB GTID組成
MariaDB的全局事物ID由下列三部分組成
”域識別符“-”服務器標識符“(server_id)-”事物識別符“
域識別符是MariaDB 10.0新引入的概念,可以將其理解為每個復制集群分配到唯一ID。域識別符主要是為了在引入多源復制后,把各事務在全局范圍內區分開來。
服務器標識符就是復制中使用的server_id系統變量。最后的事物識別符是依次增1的8字節常數值。
MariaDB的GTID是以事務為單位進行分配的。當使用不支持事務的存儲引擎時,GTID會以SQL語句為單位進行分配。
下面將詳細說明一下GTID復制相關內容。
一、搭建GTID復制從庫
從庫導入主庫的備份數據,目前mysql主要由以下兩種方式進行備份:
1、mydumper邏輯備份(或者mysqldump邏輯備份)
可以到備份目錄文件下獲取備份完成時主庫最后執行完事務的GTID.
more metadata
Started dump at: 2017-06-17 10:55:40
SHOW MASTER STATUS:
Log: mysql-bin.000056
Pos: 9637
GTID:0-64236-299476
GTID:0-64236-299476 就是后面從庫導入備份數據后,從這個GTID開始進行復制的位置。
2、xtrabackup備份
more xtrabackup_binlog_info?
mysql-bin.000104 95830984 0-691253306-60596652
0-691253306-60596652 是后面從庫數據導入后進行復制的起始位置。
搭建步驟如下:
實驗機器:10.24.64.236 主庫,10.24.64.239 從庫。
從庫導入主庫的備份數據(mydumper或者xtrabackup備份)后,執行以下命令。
a. set global gtid_slave_pos='0-64236-299476';
b. show variables like 'gtid%';確認gtid_slave_pos位置有效。
MariaDB [jira]> show variables like 'gtid%';?
+------------------------+----------------+
| Variable_name | Value |
+------------------------+----------------+
| gtid_binlog_pos | |
| gtid_binlog_state | |
| gtid_current_pos | 0-64236-299476 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_seq_no | 0 |
| gtid_slave_pos | 0-64236-299476 |
| gtid_strict_mode | OFF |
+------------------------+----------------+
c. change master to master_host='10.24.64.236',master_user='rep',master_password='xxx',master_use_gtid=slave_pos;
d.start slave; show slave status\G 確認復制搭建成功。
MariaDB [jira]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.24.64.236
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000056
Read_Master_Log_Pos: 9637
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 670
Relay_Master_Log_File: mysql-bin.000056
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...
Master_Server_Id: 64236
Master_SSL_Crl:?
Master_SSL_Crlpath:?
Using_Gtid: Slave_Pos
Gtid_IO_Pos: 0-64236-299476
二、GTID復制與傳統復制之間的切換
1、GTID復制切換到傳統復制
stop slave;
change master to master_use_gtid=no;
start slave;
shwo slave status\G?
Using_Gtid: No 可以確認已經由GTID復制切換到傳統復制。
MariaDB [test]> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.24.64.236
Master_User: rep
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000056
Read_Master_Log_Pos: 9955
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 537
Relay_Master_Log_File: mysql-bin.000056
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
..
Using_Gtid: No
Gtid_IO_Pos: 0-64236-299478
我們再在236主庫任意插入一條數據,可以發現239從庫的GTID也跟著在增長。并且和236主庫的gtid_current_pos保持一致。
GTID由原來的 Gtid_IO_Pos: 0-64236-299478 增長到現在的 gtid_slave_pos | 0-64236-299479。
MariaDB [test]> show variables like 'gtid%';
+------------------------+----------------+
| Variable_name | Value |
+------------------------+----------------+
| gtid_binlog_pos | 0-64236-299479 |
| gtid_binlog_state | 0-64236-299479 |
| gtid_current_pos | 0-64236-299479 |
| gtid_domain_id | 0 |
| gtid_ignore_duplicates | OFF |
| gtid_seq_no | 0 |
| gtid_slave_pos | 0-64236-299479 |
| gtid_strict_mode | OFF |
+------------------------+----------------+
8 rows in set (0.00 sec)
2、傳統復制切換到GTID復制
從庫執行以下命令:
stop slave;
change master to master_use_gtid=slave_pos;或者執行 change master to master_use_gtid=current_pos
start slave;
show slave status\G 確認復制已經切換成功。
三、主從GTID復制結構中Master切換
A(M)-->B(S) 切換為 A(S)<--B(M) 結構
主從GTID復制結構中Master切換非常簡單。
1、先確認從庫B已經完全追上主庫A
Master_Log_File: mysql-bin.000056 = Relay_Master_Log_File: mysql-bin.000056 && Read_Master_Log_Pos: 10390 = Exec_Master_Log_Pos: 10390?
2、A 上執行
change master to master_host='B',master_port=,master_user='rep',master_password='xxx',master_use_gtid=current_pos;start slave;
這里把 master_use_gtid 配置成 current_pos。
因為該主庫沒有做過其他數據庫的從庫,所以slave_pos為空,需要用current_pos。二者區別可以看后面的定義。
3、B 上執行 stop slave;
一主多從結構的主庫切換和一主一從切換類似,確認主從數據一致后把原來的從庫直接change到新的主庫上面就好。
四、在使用GTID的從服務器中跳過事務
場景:
在從庫某表中刪掉某條記錄,然后在主庫上執行同樣的刪除動作。
這時主庫會報錯如下:
Last_SQL_Error: Could not execute Delete_rows_v1 event on table test.tt; Can't find record in 'tt', Error_code: 1032;
handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000056, end_log_pos 10508
從庫找不到需要刪除的記錄,這時可以手動跳過這個錯誤。
方法1:
stop slave; set global gtid_slave_pos='0-64236-299482';start slave;?
show slave status\G 確認主從復制恢復正常。
方法2:
stop slave;set global sql_slave_skip_counter=1;start slave;
show slave status\G 確認主從復制恢復正常。
五、GTID使用限制
1、slave的本地寫入,需要注意,因為跟master不是同一個GTID范圍,寫入binlog的值,復制到后續從庫,容易失敗,需要使用
set sql_log_bin=0,來禁止binlog的寫入。
生產環境所有從庫已經設置為read_only(普通用戶只有select權限,有all/super權限的都不在這個范圍內)。如果因為特殊情況需要在從庫寫入數據,則先臨時關閉binlog寫入。
2、切換主庫前,必須保證主庫數據已經全部復制到將要作為新主庫的從庫。
六、常見復制錯誤處理
1、主庫進行update,delete操作,從庫發現沒有相應記錄,導致復制中斷。
Last_SQL_Error: Could not execute Delete_rows_v1 event on table test.tt; Can't find record in 'tt', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000056, end_log_pos 10508
處理方式:
根據復制報錯的binlog位置,在主庫上解析相應的binlog,確認從庫具體因為哪些數據確失導致復制中斷。
找出從庫缺失的記錄之后手動從主庫導出,再導入從庫。導入的時候,切記要先關閉binlog寫入。
set sql_log_bin=0;導入數據;set sql_log_bin=1; 然后重啟復制。
2、主庫上執行 insert操作,從庫已經有相應的記錄,導致復制中斷。
從庫報錯如下:
Last_SQL_Error: Could not execute Write_rows_v1 event on table test.tt; Duplicate entry '12' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000056, end_log_pos 10907
處理方式:
根據報錯信息可以知道從庫已經存在ID=12的記錄,因此復制再次插入同樣主鍵ID記錄時,報1062錯誤。
為了驗證這一點,可以解析主庫相應位置的binlog。
因此我們可以直接刪除從庫ID=12的記錄,重啟復制。
以上錯誤除了主庫delete操作,從庫因記錄缺失報錯可以跳過。其他錯誤都不能直接跳過,會導致主從數據不一致。
七、GTID有關的三個全局變量
select @@global.gtid_slave_pos, @@global.gtid_binlog_pos,@@global.gtid_current_pos;
gtid_slave_pos:
This variable is the GTID of the last event group replicated on a slave server, for each replication domain.
gtid_binlog_pos:
This variable is the GTID of the last event group written to the binary log, for each replication domain.
gtid_current_pos:
This variable is the GTID of the last change to the database for each replication domain. Such changes can either be master events (ie. local changes made by user or application), or replicated events originating from another master server.
總結
MariaDB10.0.2之后的GTID復制搭建與管理非常方便,整體比MySQL官方版本好用很多。主要有以下優勢:
1、MariaDB GTID可以有間斷,支持 set global sql_slave_skip_counter=1 跳過錯誤的語法。
MySQL的GTID是連續的,不支持直接跳過錯誤的語法,只能采取插入空事務來跳過相應的GTID.
2、MariaDB 復制結構中可以同時混雜傳統復制從庫和GTID復制從庫。但是MySQL不行,必須所有數據庫都開啟GTID復制。
3、MariaDB GTID和傳統復制間的切換是非常方便的無需其他配置。而MySQL就繁瑣很多,無法做到平滑過渡,需要修改主庫配置并重啟。
MariaDB官方文檔也推薦使用GTID復制。后續會琢磨一下GTID復制下的高可用工具,目標使MariaDB GTID復制在主庫失敗的情況下能自動切換,同時不丟失數據