MySQL的GTID復制


從mysql5.6開始引入全局事務標識符(GTID),即每個事務都有一個唯一的標識符。服務器上的每個事務都被分配一個唯一的事務標識符,這是一個64位非零的數值,根據事務提交的順序分配。GTID的構成是由服務器的Uuid和事務的提交順序兩部分組成的。

復制事務的時候如果啟用了全局事務標識符,不管事務被復制了多少次,事務的GTID保持不變。

注意的是:GTID被寫入二進制日志,並且只會分配給已經寫入二進制日志的事務。也就是說,如果關閉二進制日志,事務就不會分配GTID了。不管master還是slave都是這樣。所以,如果想使用slave做故障轉移,需要開啟二進制日志,如果沒有開啟二進制日志,slave就不會記下事務的GTID。

首先來配置GTID復制

首先在從上清除當前的基於filename和pos的復制狀態

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復制!因為之前兩台服務器時主從復制,因此狀態是一致的,因此不用再拷貝數據!

同步數據,設置復制賬戶都需要做!因為之前已經是主從,復制賬戶已經存在。

#主從均做如下設置
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:確保如果語句的記錄與全局事務標識符不一致,語句就報錯

設置完之后重啟服務器:

在從上做如下設置

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協商應該發送什么事務。

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>
show slave status查看復制狀態
#錯誤說明
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                                      #查看復制已經恢復正常

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM