從mysql5.6開始引入全局事務標識符(GTID),即每一個事務都有一個惟一的標識符。服務器上的每一個事務都被分配一個惟一的事務標識符,這是一個64位非零的數值,根據事務提交的順序分配。GTID的構成是由服務器的Uuid和事務的提交順序兩部分組成的。mysql
複製事務的時候若是啓用了全局事務標識符,無論事務被複制了多少次,事務的GTID保持不變。git
注意的是:GTID被寫入二進制日誌,而且只會分配給已經寫入二進制日誌的事務。也就是說,若是關閉二進制日誌,事務就不會分配GTID了。無論master仍是slave都是這樣。因此,若是想使用slave作故障轉移,須要開啓二進制日誌,若是沒有開啓二進制日誌,slave就不會記下事務的GTID。sql
首先來配置GTID複製服務器
首先在從上清除當前的基於filename和pos的複製狀態app
mysql> stop slave; Query OK, 0 rows affected (0.01 sec) mysql> reset slave all; Query OK, 0 rows affected (0.02 sec) mysql> show slave status\G Empty set (0.00 sec)
主和從均開啓GTID,設置GTID複製!由於以前兩臺服務器時主從複製,所以狀態是一致的,所以不用再拷貝數據!ide
同步數據,設置複製帳戶都須要作!由於以前已是主從,複製帳戶已經存在。測試
#主從均作以下設置 log-bin= log_slave_updates gtid-mode=on enforce-gtid-consistency
log-bin= #在基於filename和pos作主從時,沒有開啓備用服務器的二進制日誌,作gtid複製時,須要開啓二進制日誌,緣由後面會提到!
log_slave_updates: 這個是在基於filename和pos作主從時,用於作級聯複製,在MySQL5.6中左gtid好像必需要開啓這個參數,MySQL5.7再也不強制必須!
gtid-mode=on: 開啓gitd模式
enforce-gtid-consistency:確保若是語句的記錄與全局事務標識符不一致,語句就報錯。
設置完以後重啓服務器:ui
在從上作以下設置this
mysql> change master to master_host="10.0.102.214", master_port=3306,master_user="repl",master_password="123456",master_auto_position=1; Query OK, 0 rows affected, 2 warnings (0.02 sec) mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
# master_auto_position使slave在鏈接master的時候,自動與master協商應該發送什麼事務。spa
mysql> show slave status\G #與以前的複製相比,多了gitd的信息
*************************** 1. row ***************************
...........
Master_UUID: 4687e05d-f37f-11e8-8fc7-fa336351fc00 #master的UUID
Retrieved_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-2
Executed_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-2
Retrieved_Gtid_Set:這是從master獲取而來的,存儲在中繼日誌中的一組GTID.
Executed_Gtid_Set: 這是slave上執行,而且已經寫入slave的二進制日誌的一組GTID。
在從上查看二進制日誌
mysql> show binlog events; #默認讀取當前正在使用的二進制日誌 +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ | test2-bin.000001 | 4 | Format_desc | 3 | 123 | Server ver: 5.7.22-log, Binlog ver: 4 | | test2-bin.000001 | 123 | Previous_gtids | 3 | 154 | | | test2-bin.000001 | 154 | Gtid | 5 | 219 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:1' | | test2-bin.000001 | 219 | Query | 5 | 348 | use `mytest`; create table tb2(id int auto_increment primary key) | | test2-bin.000001 | 348 | Gtid | 5 | 413 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:2' | | test2-bin.000001 | 413 | Query | 5 | 476 | BEGIN | | test2-bin.000001 | 476 | Table_map | 5 | 524 | table_id: 108 (mytest.tb2) | | test2-bin.000001 | 524 | Write_rows | 5 | 564 | table_id: 108 flags: STMT_END_F | | test2-bin.000001 | 564 | Xid | 5 | 595 | COMMIT /* xid=9 */ | +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ 9 rows in set (0.01 sec)
#在二進制日誌事件中能夠看到Executed_Gtid_Set的gitd集合已經在slave上執行
gitd的複製是怎麼找到二進制日誌的複製點的?
在咱們作filename和pos的複製時,手動指定了二進制日誌的文件和位置,可是gtid怎麼找到二進制日誌的複製點的?從上面的二進制日誌看到,event有一個Previous_gtids事件,這個事件指定的是前一個二進制日誌事件的最後的gtid的數值,把當前從執行到的gtid與Previous_gtids比較,肯定二進制日誌的文件,而後再對比gtid的大小,肯定日誌的位置!由於當前是一個新開始的gitd複製,所以Previous_gtids值爲0,咱們強制輪換主的二進制,查看數據以下!
mysql> flush logs; #強制輪換二進制日誌,會進行一次顯式刷新磁盤 Query OK, 0 rows affected (0.00 sec) mysql> show binlog events in "test3-bin.000006"; #由於以前的執行了兩個事務,所以Previous_gtids指向爲1-2. +------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +------------------+------+----------------+-----------+-------------+-------------------------------------------------------------------+ | test3-bin.000006 | 4 | Format_desc | 5 | 123 | Server ver: 5.7.22-log, Binlog ver: 4 | | test3-bin.000006 | 123 | Previous_gtids | 5 | 194 | 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-2 | | test3-bin.000006 | 194 | Gtid | 5 | 259 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:3' | | test3-bin.000006 | 259 | Query | 5 | 333 | BEGIN | | test3-bin.000006 | 333 | Table_map | 5 | 381 | table_id: 109 (mytest.tb1) | | test3-bin.000006 | 381 | Write_rows | 5 | 421 | table_id: 109 flags: STMT_END_F | | test3-bin.000006 | 421 | Xid | 5 | 452 | COMMIT /* xid=40 */ | | test3-bin.000006 | 452 | Gtid | 5 | 517 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:4' |
咱們知道GTID是由服務器的UUID+事務的執行順序組成的,服務器的UUID存在於datadir指定目錄下面:
mysql> show variables like "datadir"; +---------------+--------------+ | Variable_name | Value | +---------------+--------------+ | datadir | /data/mysql/ | +---------------+--------------+ 1 row in set (0.00 sec) mysql> system cat /data/mysql/auto.cnf; #服務器的UUID [auto] server-uuid=4687e05d-f37f-11e8-8fc7-fa336351fc00
上面咱們搭建了一個簡易的GITD複製,那麼GTID是怎麼複製的,GTID的複製原理是什麼?
master更新數據時,會在事務前產生GTID,一同記錄到binlog日誌中。 slave端的i/o線程將變動的binlog,寫入到本地的relay log中。 sql線程從relay log中獲取GTID,而後對比slave端的binlog是否有記錄。【對比本地的binlog中是否有記錄,所以slave須要開通二進制日誌】 若是有記錄,說明該GTID的事務已經執行,slave會忽略。 若是沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
查看當前master和從的二進制日誌點和gtid值!
##在master上 mysql> show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | test3-bin.000006 | 1226 | | | 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-6 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) mysql> #在從上執行 mysql> show master status; +------------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+------------------------------------------+ | test2-bin.000002 | 194 | | | 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-6 | +------------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec)
#能夠看到日誌名稱不同,日誌的pos不同,可是gtid倒是同樣的
測試在從上插入一條數據:
mysql> insert into tb1 select null; #插入的是自增主鍵的數值 Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 #查看二進制日誌中的事件,是在begin開始一個事務以前,寫入了GTID的數值 | test3-bin.000006 | 1226 | Gtid | 5 | 1291 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:7' | | test3-bin.000006 | 1291 | Query | 5 | 1365 | BEGIN | | test3-bin.000006 | 1365 | Table_map | 5 | 1413 | table_id: 109 (mytest.tb1) | | test3-bin.000006 | 1413 | Write_rows | 5 | 1453 | table_id: 109 flags: STMT_END_F | | test3-bin.000006 | 1453 | Xid | 5 | 1484 | COMMIT /* xid=67 */
mysql> show variables like "binlog_format"; #日誌格式是row
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
1 row in set (0.00 sec) |
在從上查看二進制日誌
#前面執行了flush logs命令!
mysql> show binlog events in "test2-bin.000002"; +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ | test2-bin.000002 | 4 | Format_desc | 3 | 123 | Server ver: 5.7.22-log, Binlog ver: 4 | | test2-bin.000002 | 123 | Previous_gtids | 3 | 194 | 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-6 | | test2-bin.000002 | 194 | Gtid | 5 | 259 | SET @@SESSION.GTID_NEXT= '4687e05d-f37f-11e8-8fc7-fa336351fc00:7' | | test2-bin.000002 | 259 | Query | 5 | 322 | BEGIN | | test2-bin.000002 | 322 | Table_map | 5 | 370 | table_id: 110 (mytest.tb1) | | test2-bin.000002 | 370 | Write_rows | 5 | 410 | table_id: 110 flags: STMT_END_F | | test2-bin.000002 | 410 | Xid | 5 | 441 | COMMIT /* xid=40 */ | +------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+ 7 rows in set (0.00 sec)
使用GTID作故障轉移
#主從上都有一張這樣的表,數據是同樣的 mysql> desc tb2; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | +-------+---------+------+-----+---------+----------------+ 1 row in set (0.00 sec) #如今在從從上插入一條數據 mysql> insert into tb2 select 4; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 #在主上也插入一條數據 mysql> insert into tb2 select 4; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.0.102.214 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: test3-bin.000007 Read_Master_Log_Pos: 452 Relay_Log_File: test2-relay-bin.000007 Relay_Log_Pos: 407 Relay_Master_Log_File: test3-bin.000007 Slave_IO_Running: Yes Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 1062 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '4687e05d-f37f-11e8-8fc7-fa336351fc00:8' at master log test3-bin.000007, end_log_pos 421. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Skip_Counter: 0 Exec_Master_Log_Pos: 194 Relay_Log_Space: 959 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: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 1062 Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '4687e05d-f37f-11e8-8fc7-fa336351fc00:8' at master log test3-bin.000007, end_log_pos 421. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Replicate_Ignore_Server_Ids: Master_Server_Id: 5 Master_UUID: 4687e05d-f37f-11e8-8fc7-fa336351fc00 Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: 181203 10:01:08 Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-8 Executed_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-7, e2bd1bae-f5cb-11e8-9c8c-fa1dae125200:1 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) mysql>
#錯誤說明
Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '4687e05d-f37f-11e8-8fc7-fa336351fc00:8' at master log test3-bin.000007, end_log_pos 421. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Retrieved_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-8 #從接收到的gtid, gtid爲8的序列沒有執行, Executed_Gtid_Set: 4687e05d-f37f-11e8-8fc7-fa336351fc00:1-7, #從執行的gtid,可是卻執行了下面的一個gtid e2bd1bae-f5cb-11e8-9c8c-fa1dae125200:1
咱們知道是重複了數值,所以忽略掉這一條gitd的執行事務便可!
mysql> select @@gtid_next; #查看下一個要執行的事務,默認是自動選擇 +-------------+ | @@gtid_next | +-------------+ | AUTOMATIC | +-------------+ 1 row in set (0.00 sec) mysql> set gtid_next="4687e05d-f37f-11e8-8fc7-fa336351fc00:8"; #咱們把gtid_next設置爲要忽略的哪個事務的gtid Query OK, 0 rows affected (0.00 sec) mysql> begin; #執行一個空的事務 Query OK, 0 rows affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.01 sec) mysql> set gtid_next="AUTOMATIC"; #把gtid_next設置爲原來的AUTOMATIC Query OK, 0 rows affected (0.00 sec) mysql> start slave sql_thread; #開啓sql線程 Query OK, 0 rows affected (0.02 sec) mysql> show slave status\G #查看複製已經恢復正常