【MySQL】基于GTID的復制(后包含5.7復制建議開啟的參數(shù))

一、GTID(Global Transaction Identifieds)

  1. GTID從MySQL 5.6.2版本開始支持,并在5.6.10版本之后開始完善,所以在其之間的版本并不推薦使用。
  2. GTID分為兩個部分,一部分是服務(wù)的uuid,保存在MySQL數(shù)據(jù)目錄的auto.cnf文件中,這個文件不能刪除,非常重要,這部分是不會變的。而另一部分就是事務(wù)的ID,會隨著事務(wù)的增加而遞增。
    GTID:724afcc2-29d6-11e4-9902-000c290c0121:1-362
    UUID:724afcc2-29d6-11e4-9902-000c290c0121
    transactionId:1-362
    官方說明:GTID = source_id:transaction_id
    在整個復制結(jié)構(gòu)中,GTID是不會變化的,幾時在多個連環(huán)主從中也不會變,例如:ServerA --->ServerB ---->ServerC
    GTID從在ServerA ,ServerB,ServerC 中都是一樣的。

二、GTID工作原理

  1. master更新數(shù)據(jù)時,會在事務(wù)前產(chǎn)生GTID,一同記錄到binlog日志中。
  2. slave端的i/o 線程將變更的binlog,寫入到本地的relay log中。
  3. sql線程從relay log中獲取GTID,然后對比slave端的binlog是否有記錄。
  4. 如果有記錄,說明該GTID的事務(wù)已經(jīng)執(zhí)行,slave會忽略。
  5. 如果沒有記錄,slave就會從relay log中執(zhí)行該GTID的事務(wù),并記錄到binlog。
  6. 在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描。

三、GTID特點

  1. 一個事務(wù)對應(yīng)一個唯一ID,一個GTID在一個服務(wù)器上只會執(zhí)行一次
  2. GTID是用來代替?zhèn)鹘y(tǒng)復制的方法,GTID復制與普通復制模式的最大不同就是不需要指定二進制文件名和位置
  3. 減少手工干預和降低服務(wù)故障時間,當主機掛了之后通過軟件從眾多的備機中提升一臺備機為主機

四、故障處理原理

那么GTID復制是怎么實現(xiàn)自動同步,自動對應(yīng)位置的呢?
例如:ServerC <-----ServerA ----> ServerB
主機ServerA
備機:ServerB,ServerC


上圖的意思是:

Server1(Master)崩潰,根據(jù)從上show slave status獲得Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已經(jīng)跟上了主,Server3(Slave)沒有跟上主。這時要是把Server2提升為主,Server3變成Server2的從。這時在Server3上執(zhí)行change的時候需要做一些計算,這里就不做說明了,相對來說是比較麻煩的。

這個問題在5.6的GTID出現(xiàn)后,就顯得非常的簡單。由于同一事務(wù)的GTID在所有節(jié)點上的值一致,那么根據(jù)Server3當前停止點的GTID就能定位到Server2上的GTID。甚至由于MASTER_AUTO_POSITION功能的出現(xiàn),我們都不需要知道GTID的具體值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。

原理:

當ServerC鏈接ServerB 之后,首先在自己的二進制文件中找到從ServerA 傳過來的最新的GTID,然后將這個GTID 發(fā)送到ServerB ,ServerB 獲得這個GTID之后,就開始從這個GTID的下一個GTID
開始發(fā)送事務(wù)給ServerC。這種自我尋找復制位置的模式減少事務(wù)丟失的可能性以及故障恢復的時間。
按照另一種說法就是:從服務(wù)器連接到主服務(wù)器之后,把自己執(zhí)行過的GTID(Executed_Gtid_Set)<SQL線程> 、獲取到的GTID(Retrieved_Gtid_Set)<IO線程>發(fā)給主服務(wù)器,主服務(wù)器把從服務(wù)器缺少的GTID及對應(yīng)的transactions發(fā)過去補全即可。當主服務(wù)器掛掉的時候,找出同步最成功的那臺從服務(wù)器,直接把它提升為主即可。如果硬要指定某一臺不是最新的從服務(wù)器提升為主, 先change到同步最成功的那臺從服務(wù)器, 等把GTID全部補全了,就可以把它提升為主了。

五、GTID的限制

  1. 不支持非事務(wù)引擎
  2. 不支持create table ... select 語句復制(主庫直接報錯)
    原理:( 會生成兩個sql,一個是DDL創(chuàng)建表SQL,一個是insert into 插入數(shù)據(jù)的sql。
    由于DDL會導致自動提交,所以這個sql至少需要兩個GTID,但是GTID模式下,只能給這個sql生成一個GTID )
  3. 不允許一個SQL同時更新一個事務(wù)引擎表和非事務(wù)引擎表
  4. 在一個復制組中,必須要求統(tǒng)一開啟GTID或者是關(guān)閉GTID
  5. 開啟GTID需要重啟(5.7除外)
  6. 開啟GTID后,就不再使用原來的傳統(tǒng)復制方式
  7. 對于create temporary table 和 drop temporary table語句不支持
  8. 不支持sql_slave_skip_counter
  9. 從傳統(tǒng)復制模式轉(zhuǎn)為GTID模式比較麻煩(不建議轉(zhuǎn)換,如需轉(zhuǎn)換,建議重新搭建)

六、引入GTID的意義

  1. 因為清楚了GTID的格式,所以通過UUID可以知道這個事務(wù)在哪個實例上提交的。
  2. 通過GTID可以極方便的進行復制結(jié)構(gòu)上的故障轉(zhuǎn)移,新主設(shè)置,參考上面故障處理原理。

七、復制環(huán)境搭建

1、從支持GTID后,MySQL添加了部分參數(shù)

mysql> show variables like '%gtid%';   
+---------------------------------+-----------+   
| Variable_name                  | Value      |   
+---------------------------------+-----------+   
| binlog_gtid_simple_recovery     | OFF       |   
| enforce_gtid_consistency        | OFF       |  
| gtid_deployment_step            | OFF       |  
| gtid_executed                   |           |  
| gtid_mode                       | OFF       |  
| gtid_next                       | AUTOMATIC |  
| gtid_owned                      |           |  
| gtid_purged                     |           |  
| simplified_binlog_gtid_recovery | OFF       |  
+---------------------------------+-----------+

2、主要的搭建方法與傳統(tǒng)的搭建方式基本沒什么區(qū)別,配置文件需添加以下參數(shù)

server_id = 249
log_bin = mysql-bin
gtid_mode = on
enforce_gtid_consistency = 1
log_slave_updates = 1
binlog_format = row #必須是row

這需要注意的是,gtid模式一定要開啟gtid_mode、enforce_gtid_consistency和log_slave_updates 這三個參數(shù),任意一個不開啟都會報錯

錯誤如下:

6512 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates 6512 [ERROR] Aborting 9860 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency 9860 [ERROR] Aborting

3、此時,我們可以查看數(shù)據(jù)庫的uuid:

mysql>  select  @@server_uuid;   
+--------------------------------------+  
|  @@server_uuid                       |  
+--------------------------------------+  
| 4e659069-3cd8-11e5-9a49-001c4270714e |  
+--------------------------------------+

4、然后,我們需要在從庫(備份庫)上change來切換/設(shè)置它的主庫

這里需要注意的是:

不使用gtid的change的方法:

mysql> change master to  master_host='127.0.0.1',master_user='rep',master_password='rep',master_log_file='mysql-bin3306.000001',master_log_pos=151,/*master_auto_position=1*/;

如果還是按照傳統(tǒng)的方式來change的話會報錯:

ERROR 1776 (HY000): Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active.

所以此時,我們需要的是使用master_auto_position這個參數(shù)去代替MASTER_LOG_FILE及MASTER_LOG_POS

語句如下:

mysql> change master to  master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3306,master_auto_position=1;

如果從庫之前有過當主從的情況,或者不是新搭建環(huán)境的情況,那么還需要執(zhí)行reset master語句來重置一下master

5、之后執(zhí)行start slave來開啟主從復制即可。

6、驗證,在主庫上查看進程可看到如下情況:

mysql> show processlist\G;  
***************************  1. row ***************************  
Id: 38  
User: rep  
Host: localhost:52321  
db: NULL  
Command: Binlog Dump GTID #通過GTID復制  
Time: 48  
State: Master has sent all binlog to slave; waiting for binlog to be updated  
Info: NULL  
Rows_sent: 0  
Rows_examined: 0

八、測試

1、測試復制的故障轉(zhuǎn)移

模擬服務(wù)器A(master)掛掉,現(xiàn)在需要將服務(wù)器B或者服務(wù)器C設(shè)置為主,而另一個設(shè)置為從

1.1

首先使用show slave status查看服務(wù)器B和服務(wù)器C的進度

服務(wù)器B:

Master_Log_File: mysql-bin3306.000002  
Read_Master_Log_Pos: 4156773 Exec_Master_Log_Pos: 4156773

服務(wù)器C:

Master_Log_File: mysql-bin3306.000001  
Read_Master_Log_Pos: 83795320 Exec_Master_Log_Pos: 8379532

從上面可以看出服務(wù)器B的進度比服務(wù)器C更接近master

1.2

如果在傳統(tǒng)的復制情況下,將C設(shè)置為B的從庫,那將需要之前主句的log_pos和當前要設(shè)置成主庫的log_pos,此時計算很容易出錯,而且比較麻煩

那么在gtid的情況下,因為同一事物的GTID在所有節(jié)點上的值是一樣的,所以可以直接將C的主庫定位到B即可,但需要注意的是,此時千萬不能執(zhí)行reset master,不然C會從最先的GTID開始執(zhí)行

具體順序如下:

mysql> stop slave;   
Query OK, 0 rows affected (0.02 sec)

mysql>  change master to master_host='127.0.0.1',master_user='rep',master_password='rep',master_port=3307,master_auto_position=1; #指定到另一個比較接近主的從上。   
Query OK, 0 rows affected, 2 warnings (0.02 sec)   
mysql> start slave; #成功的切換到新主   
Query OK, 0 rows affected (0.03 sec)

此時即完成了新主的切換

2、測試跳過復制錯誤

模擬出現(xiàn)了錯誤

mysql> show slave status\G;  
***************************  1. row ***************************  
Slave_IO_State: Waiting for master to send event  
Master_Host: 127.0.0.1  
Master_User: rep  
Master_Port: 3306  
Connect_Retry: 60  
Master_Log_File: mysql-bin3306.000001  
Read_Master_Log_Pos: 38260944  
Relay_Log_File: mysqld-relay-bin3307.000002  
Relay_Log_Pos: 369  
Relay_Master_Log_File: mysql-bin3306.000001  
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: 1008  
Last_Error: Error 'Can't drop  database  'mablevi'; database doesn't exist'  on query. Default  database: 'mablevi'. Query: 'drop database mablevi'  
Skip_Counter: 0  
Exec_Master_Log_Pos: 151  
Relay_Log_Space: 38261371  
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: 1008  
Last_SQL_Error: Error 'Can't drop  database  'mablevi'; database doesn't exist'  on query. Default  database: 'mablevi'. Query: 'drop database mablevi'  
Replicate_Ignore_Server_Ids:  
Master_Server_Id: 1  
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e  
Master_Info_File: mysql.slave_master_info  
SQL_Delay: 0 #通過在change的時候指定,如:change master to master_delay=600,延遲10分鐘同步。  
SQL_Remaining_Delay: NULL  
Slave_SQL_Running_State:  
Master_Retry_Count: 86400  
Master_Bind:  
Last_IO_Error_Timestamp:  
Last_SQL_Error_Timestamp: 150810  23:38:39  
Master_SSL_Crl:  
Master_SSL_Crlpath:  
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48  
Executed_Gtid_Set:  
Auto_Position: 1

在傳統(tǒng)的復制情況下,只需執(zhí)行set global sql_slave_skip_counter=1;就好了,但在gtid的模式下不行,因為是通過gtid來復制的,需要跳過這個事物來繼續(xù)復制,這個事務(wù)可以在主上的binlog里面查看:因為不知道找哪個GTID上出錯,所以也不知道如何跳過哪個GTID。但在show slave status里的信息里可以找到在執(zhí)行Master里的POS:454,

Relay_Log_File: localhost-relay-bin.000005
Relay_Log_Pos: 454
Exec_Master_Log_Pos: 151(這個暫時不知道作用)

的時候報錯,所以通過mysqlbinlog找到了GTID:

# at 454 #150810  22:57:45 server id 1 end_log_pos 599 CRC32 0x5e14d88f GTID [commit=yes]  
SET  @@SESSION.GTID_NEXT=  '4e659069-3cd8-11e5-9a49-001c4270714e:1'/*!*/;

(需要驗證)
或者在show slave status中找到Retrieved_Gtid_Set:4e659069-3cd8-11e5-9a49-001c4270714e:1

找到了這個GTID之后,就可以接著執(zhí)行以下(要按順序):

mysql> stop slave;  
Query OK, 0 rows affected (0.01 sec)  
mysql>  set  session  gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1'; #在session里設(shè)置gtid_next,即跳過這個GTID  
Query OK, 0 rows affected (0.01 sec)  
mysql>  begin; #開啟一個事務(wù)  
Query OK, 0 rows affected (0.00 sec)  
mysql>  commit;  
Query OK, 0 rows affected (0.01 sec)  
mysql>  SET SESSION GTID_NEXT = AUTOMATIC; #把gtid_next設(shè)置回來  
Query OK, 0 rows affected (0.00 sec)  
mysql> start slave; #開啟復制  
Query OK, 0 rows affected (0.01 sec)

之后show slave status查看即可發(fā)現(xiàn)已跳過了該錯誤繼續(xù)同步

3、跳過錯誤/事務(wù)例子2

mysql > stop slave;  
Query OK, 0 ROWS affected (0.05 sec)  
mysql > CHANGE master TO MASTER_DELAY=600;  
Query OK, 0 ROWS affected (0.27 sec)    
mysql > START slave;  
Query OK, 0 ROWS affected, 1 warning (0.06 sec)

master 原本是正常的, 然后意外地執(zhí)行了 truncate table:

mysql > INSERT INTO t SET title='c';  
Query OK, 1 ROW affected (0.03 sec)  
mysql > INSERT INTO t SET title='d';  
Query OK, 1 ROW affected (0.05 sec)  
mysql > SHOW master STATUS \G  
*************************** 1\. ROW ***************************  
File: black-bin.000001  
POSITION: 2817  
Binlog_Do_DB:  
Binlog_Ignore_DB:  
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-10  
ROW IN SET (0.00 sec)  
mysql > TRUNCATE TABLE t;  
Query OK, 0 ROWS affected (0.15 sec)  
mysql > SHOW master STATUS \G  
*************************** 1\. ROW ***************************  
File: black-bin.000001  
POSITION: 2948  
Binlog_Do_DB:  
Binlog_Ignore_DB:  
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11  
ROW IN SET (0.00 sec)

slave有延遲, 雖然已經(jīng)獲取到了gtid及對應(yīng)的events, 但是并未執(zhí)行:

mysql > SHOW slave STATUS \G  
*************************** 1\. ROW ***************************  
Slave_IO_State: Waiting FOR master TO send event  
.......  
.......  
SQL_Delay: 600  
SQL_Remaining_Delay: 565  
Slave_SQL_Running_State: Waiting until MASTER_DELAY seconds after master executed event  
Master_Retry_Count: 86400  
Master_Bind:  
Last_IO_Error_Timestamp:  
Last_SQL_Error_Timestamp:  
Master_SSL_Crl:  
Master_SSL_Crlpath:  
Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11  
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-8  
Auto_Position: 1  
ROW IN SET (0.00 sec)

要想辦法在slave中跳過 GTID:0c005b76-d3c7-11e2-a27d-274c063b18c4:11, 也就是那條truncate table語句 。
辦法就是設(shè)置GTID_NEXT,然后提交一個空的事務(wù)。

mysql > stop slave;  
Query OK, 0 ROWS affected (0.03 sec)  
mysql > SET session gtid_next='0c005b76-d3c7-11e2-a27d-274c063b18c4:11';  
Query OK, 0 ROWS affected (0.00 sec)  
mysql > BEGIN; commit;  
Query OK, 0 ROWS affected (0.00 sec)  
Query OK, 0 ROWS affected (0.01 sec)  
mysql >SET SESSION GTID_NEXT = AUTOMATIC;  
Query OK, 0 ROWS affected (0.00 sec)  
mysql > START slave;  
Query OK, 0 ROWS affected, 1 warning (0.07 sec)

查看復制狀態(tài)

mysql > SHOW slave STATUS \G  
*************************** 1\. ROW ***************************  
Slave_IO_State: Waiting FOR master TO send event  
.......  
.......  
Retrieved_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:9-11  
Executed_Gtid_Set: 0c005b76-d3c7-11e2-a27d-274c063b18c4:1-11  
Auto_Position: 1  
ROW IN SET (0.00 sec)  
mysql > SELECT * FROM t;  
+----+-------+  
| id | title |  
+----+-------+  
| 1  | a     |  
| 2  | b     |  
| 3  | c     |  
| 4  | d     |  
+----+-------+  
ROWS IN SET (0.00 sec)

成功跳過 truncate table, 當然此時主從的數(shù)據(jù)已經(jīng)不一致了。

注意:通過GTID的復制都是沒有指定MASTER_LOG_FILE和MASTER_LOG_POS的,所以通過GTID復制都是從最先開始的事務(wù)開始,除非在自己的binlog里面有執(zhí)行過之前的記錄,才會繼續(xù)后面的執(zhí)行。

4、 要是事務(wù)日志被purge例子:

mysql> show master logs;   
+----------------------+-----------+   
| Log_name | File_size |   
+----------------------+-----------+   
| mysql-bin3306.000001  |  38260944   |   
+----------------------+-----------+   
1 row in  set (0.00 sec)  
mysql> flush logs;  
Query OK, 0 rows affected (0.03 sec)  
mysql> show tables;  
+---------------+   
| Tables_in_mmm |  
+---------------+  
| patent_family |  
| t1 |  
| t2 |  
+---------------+  
3 rows in  set (0.01 sec)  
mysql>  create  table t3(id int)engine = tokudb;  
Query OK, 0 rows affected (0.02 sec)  
mysql>  insert  into t3 values(3),(4);  
Query OK, 2 rows affected (0.05 sec) Records: 2 Duplicates: 0 Warnings: 0  
mysql> flush logs;  
Query OK, 0 rows affected (0.02 sec)  
mysql>  create  table ttt(id int)engine = tokudb;  
Query OK, 0 rows affected (0.02 sec)  
mysql>  insert  into ttt values(1),(2),(3),(4),(5);  
Query OK, 5 rows affected (0.03 sec) Records: 5 Duplicates: 0 Warnings: 0  
mysql> show master logs;  
+----------------------+-----------+  
| Log_name | File_size |  
+----------------------+-----------+  
| mysql-bin3306.000001  |  38260995  |  
| mysql-bin3306.000002  |  656  |  
| mysql-bin3306.000003  |  619  |  
+----------------------+-----------+  
3 rows in  set (0.00 sec)  
mysql> purge binary logs to  'mysql-bin3306.000003'; #日志被purge  Query OK, 0 rows affected (0.02 sec)  
mysql> show master logs; #日志被purge之后等下的binlog  
+----------------------+-----------+  
| Log_name | File_size |  
+----------------------+-----------+  
| mysql-bin3306.000003  |  619  |  
+----------------------+--------+   

3308登陸之后執(zhí)行:

mysql> change master to master_host='127.0.0.1',master_user='rep',master_password='rep',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.02 sec)  
mysql> show slave status\G 
***************************  1. row ***************************  
Slave_IO_State:  
Master_Host: 127.0.0.1  
Master_User:  
rep Master_Port: 3306  
Connect_Retry: 60  
Master_Log_File:  
Read_Master_Log_Pos: 4  
Relay_Log_File: mysqld-relay-bin3308.000001  
Relay_Log_Pos: 4  
Relay_Master_Log_File:  
Slave_IO_Running: No  
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: 0  
Relay_Log_Space: 151  
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: 1236  
Last_IO_Error: Got fatal error 1236  from master when reading data from  binary  log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'  
Last_SQL_Errno: 0  
Last_SQL_Error:  
Replicate_Ignore_Server_Ids:  
Master_Server_Id: 1  
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e  Master_Info_File: /var/lib/mysql3/master.info  
SQL_Delay: 0  
SQL_Remaining_Delay: NULL  
Slave_SQL_Running_State: Slave has read  all relay log; waiting for the slave I/O thread to  update it  
Master_Retry_Count: 86400  
Master_Bind:  
Last_IO_Error_Timestamp: 150811  00:02:50  
Last_SQL_Error_Timestamp:  
Master_SSL_Crl:  
Master_SSL_Crlpath:  
Retrieved_Gtid_Set:  
Executed_Gtid_Set:  
Auto_Position: 1

報錯:

Last_IO_Errno: 1236  
Last_IO_Error: Got fatal error 1236  from master when reading data from  binary  log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'

這里需要解決的是:Slave如何跳過purge的部分,而不是在最先開始的事務(wù)執(zhí)行。

在主上執(zhí)行,查看被purge的GTID:

mysql> show global variables like  'gtid_purged';  
+---------------+-------------------------------------------+  
| Variable_name | Value |  
+---------------+-------------------------------------------+  
| gtid_purged | 4e659069-3cd8-11e5-9a49-001c4270714e:1-50  |  
+---------------+-------------------------------------------+  
1 row in  set (0.00 sec) 

在從上執(zhí)行,跳過這個GTID:

mysql> stop slave;  
Query OK, 0 rows affected (0.00 sec)  
mysql>  set  global  gtid_purged  =  '4e659069-3cd8-11e5-9a49-001c4270714e:1-50';  
Query OK, 0 rows affected (0.02 sec)  
mysql> reset master;  
Query OK, 0 rows affected (0.04 sec)  
mysql> start slave;  
Query OK, 0 rows affected (0.01 sec)  

要是出現(xiàn):

ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set  when  @@GLOBAL.GTID_EXECUTED is empty. 

則需要執(zhí)行:

mysql > reset master;

到這從的同步就正常了

5、通過另一個從庫恢復從庫數(shù)據(jù)

比如一臺從庫誤操作,數(shù)據(jù)丟失了,可以通過另一個從庫來進行恢復:、

slaveB(3308):

mysql>  use mmm  
Database changed  
mysql> show tables;  
+---------------+  
| Tables_in_mmm |  
+---------------+  
| patent_family |  
| t |  
| tt |  
+---------------+   
3 rows in  set (0.00 sec)  
mysql>  truncate  table tt;#誤操作,把記錄刪除了  
Query OK, 0 rows affected (0.02 sec)  
mysql> show slave status\G  
***************************  1. row ***************************  
Slave_IO_State: Waiting for master to send event  
Master_Host: 127.0.0.1  
Master_User: rep  
Master_Port: 3306  
Connect_Retry: 60  
Master_Log_File: mysql-bin3306.000001  
Read_Master_Log_Pos: 38260553  
Relay_Log_File: mysqld-relay-bin3308.000002  
Relay_Log_Pos: 38260771  
Relay_Master_Log_File: mysql-bin3306.000001  
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: 38260553  
Relay_Log_Space: 38260980  
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: 1  
Master_UUID: 4e659069-3cd8-11e5-9a49-001c4270714e  
Master_Info_File: /var/lib/mysql3/master.info  
SQL_Delay: 0 #延遲同步  
SQL_Remaining_Delay: NULL  
Slave_SQL_Running_State: Slave has read  all relay log; waiting for the slave I/O thread to  update it  
Master_Retry_Count: 86400  
Master_Bind:  
Last_IO_Error_Timestamp:  
Last_SQL_Error_Timestamp:  
Master_SSL_Crl:  
Master_SSL_Crlpath:  
Retrieved_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-46  Executed_Gtid_Set: 081ccacf-3ce4-11e5-9a95-001c4270714e:1, #多出了一個GTID(本身實例執(zhí)行的事務(wù)) 4e659069-3cd8-11e5-9a49-001c4270714e:1-46  
Auto_Position: 1  

數(shù)據(jù)被誤刪除之后,最好停止復制:

mysql > stop slave;   

恢復數(shù)據(jù)從slave1(3307)上備份數(shù)據(jù),并還原到slave2(3308)中。
備份:

mysqldump -uzjy -p123456 -h127.0.0.1  -P3307 --default-character-set=utf8 --set-gtid-purged=ON -B mmm > mmm1.sql   

在還原到slaveB的時候需要在slave2上執(zhí)行:reset master; 不然會報錯:

ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set  when  @@GLOBAL.GTID_EXECUTED is empty. 

還原:

 mysql -uroot -p123456 -h127.0.0.1  -P3308 --default-character-set=utf8 < mmm.sql   

開啟同步:

mysql> start slave;   
Query OK, 0 rows affected, 1 warning (0.03 sec)   

這時候你會發(fā)現(xiàn)誤刪除的數(shù)據(jù)已經(jīng)被還原,并且復制也正常。因為根據(jù)GTID的原理,通過slave1的備份直接可以和Master進行同步。

這里備份注意的一點是:在備份開啟GTID的實例里,需要指定 --set-gtid-purged參數(shù),否則會報warning:

Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events

備份文件里面會出現(xiàn):

SET @@GLOBAL.GTID_PURGED='4e659069-3cd8-11e5-9a49-001c4270714e:1-483';

還原的時候會要求先在實例上reset master,不然會報錯:

Warning: Using a password on the command line interface can be insecure. ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

指定--set-gtid-purged=ON參數(shù),出現(xiàn)GTID_PURGED,直接還原的時候執(zhí)行,從庫不需要其他操作就可以直接change到主。

總結(jié):

要是主從結(jié)構(gòu)只有一臺Master和一臺Slave對于GTID來說就沒有優(yōu)勢了,而對于2臺主以上的結(jié)構(gòu)優(yōu)勢異常明顯,可以在數(shù)據(jù)不丟失的情況下切換新主。
使用GTID需要注意的是:在構(gòu)建主從復制之前,在一臺將成為主的實例上進行一些操作(如數(shù)據(jù)清理等),通過GTID復制,這些在主從成立之前的操作也會被復制到從服務(wù)器上,引起復制失敗。即:通過GTID復制都是從最先開始的事務(wù)日志開始,即使這些操作在復制之前執(zhí)行。比如在server1上執(zhí)行一些drop、delete的清理操作,接著在server2上執(zhí)行change的操作,會使得server2也進行server1的清理操作。

建議開啟的參數(shù):

relay_log_recovery
當slave從庫宕機后,假如relay-log損壞了,導致一部分中繼日志沒有處理,則自動放棄所有未執(zhí)行的relay-log,并且重新從master上獲取日志,這樣就保證了relay-log的完整性。默認情況下該功能是關(guān)閉的,將relay_log_recovery的值設(shè)置為 1時,可在slave從庫上開啟該功能,建議開啟。

slave_parallel_workers和slave_parallel_type(提升主從復制效率)
在MySQL 5.7中,引入了基于組提交的并行復制(Enhanced Multi-threaded Slaves),設(shè)置參數(shù)slave_parallel_workers>0并且global.slave_parallel_type=‘LOGICAL_CLOCK’
變量slave-parallel-type可以有兩個值:DATABASE 默認值,基于庫的并行復制方式;LOGICAL_CLOCK:基于組提交的并行復制方式

參考:

http://www.cnblogs.com/zhoujinyi/p/4717951.html
https://www.cnblogs.com/andy6/p/6979590.html
https://blog.csdn.net/anzhen0429/article/details/77658663

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容