Mysql基於GTID複製模式-運維小結 (完整篇)

 

先來看mysql5.6主從同步操做時遇到的一個報錯:
mysql> change master to master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_log_file='mysql-bin.000004',master_log_pos=49224392;
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.html

產生緣由:主從數據庫雙方都開啓了gtid功能(經過命令"show variables like '%gtid%';"查看),gtid功能是mysql5.6版本出來的新特性! mysql

解決辦法:
1)方法一: 提早執行下面語句
mysql> change master to master_auto_position=1;
mysql> change master to master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_log_file='mysql-bin.000004',master_log_pos=49224392; git

2)方法二: 在change語句後面添加
mysql> change master to  master_host='192.168.10.59',master_user='repli',master_password='repli@123',master_port=3306,master_auto_position=1;sql

                                                                                                                                                                                         

1、GTID概念介紹數據庫

GTID即全局事務ID (global transaction identifier), 其保證爲每個在主上提交的事務在複製集羣中能夠生成一個惟一的ID。GTID最初由google實現,官方MySQL在5.6才加入該功能。mysql主從結構在一主一從狀況下對於GTID來講就沒有優點了,而對於2臺主以上的結構優點異常明顯,能夠在數據不丟失的狀況下切換新主。使用GTID須要注意: 在構建主從複製以前,在一臺將成爲主的實例上進行一些操做(如數據清理等),經過GTID複製,這些在主從成立以前的操做也會被複制到從服務器上,引發複製失敗。也就是說經過GTID複製都是從最早開始的事務日誌開始,即便這些操做在複製以前執行。好比在server1上執行一些drop、delete的清理操做,接着在server2上執行change的操做,會使得server2也進行server1的清理操做。vim

GTID其實是由UUID+TID (即transactionId)組成的。其中UUID(即server_uuid) 產生於auto.conf文件(cat /data/mysql/data/auto.cnf),是一個MySQL實例的惟一標識。TID表明了該實例上已經提交的事務數量,而且隨着事務提交單調遞增,因此GTID可以保證每一個MySQL實例事務的執行(不會重複執行同一個事務,而且會補全沒有執行的事務)。GTID在一組複製中,全局惟一。 下面是一個GTID的具體形式 :安全

mysql> show master status;
+-----------+----------+--------------+------------------+-------------------------------------------+
| File      | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+-----------+----------+--------------+------------------+-------------------------------------------+
| on.000003 |      187 |              |                  | 7286f791-125d-11e9-9a9c-0050568843f8:1-362|
+-----------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)

GTID:7286f791-125d-11e9-9a9c-0050568843f8:1-362
UUID:7286f791-125d-11e9-9a9c-0050568843f8
transactionId:1-362

在整個複製架構中GTID 是不變化的,即便在多個連環主從中也不會變。

例如:ServerA --->ServerB ---->ServerC 
GTID從在ServerA ,ServerB,ServerC 中都是同樣的。

瞭解了GTID的格式,經過UUID能夠知道這個事務在哪一個實例上提交的。經過GTID能夠極方便的進行復制結構上的故障轉移,新主設置,這就很好地解決了下面這個圖所展示出來的問題。bash

如圖, Server1(Master)崩潰,根據從上show slave status得到Master_log_File/Read_Master_Log_Pos的值,Server2(Slave)已經跟上了主,Server3(Slave)沒有跟上主。這時要是把Server2提高爲主,Server3變成Server2的從。這時在Server3上執行change的時候須要作一些計算。服務器

這個問題在5.6的GTID出現後,就顯得很是的簡單。因爲同一事務的GTID在全部節點上的值一致,那麼根據Server3當前中止點的GTID就能定位到Server2上的GTID。甚至因爲MASTER_AUTO_POSITION功能的出現,咱們都不須要知道GTID的具體值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就能夠直接完成failover的工做。session

======  GTID和Binlog的關係  ======

-  GTID在binlog中的結構

-  GTID event 結構

-  Previous_gtid_log_event
Previous_gtid_log_event 在每一個binlog 頭部都會有每次binlog rotate的時候存儲在binlog頭部Previous-GTIDs在binlog中只會存儲在這臺機器上執行過的全部binlog,不包括手動設置gtid_purged值。換句話說,若是你手動set global gtid_purged=xx; 那麼xx是不會記錄在Previous_gtid_log_event中的。

-  GTID和Binlog之間的關係是怎麼對應的呢? 如何才能找到GTID=? 對應的binlog文件呢?

假設有4個binlog: bin.001,bin.002,bin.003,bin.004
bin.001 : Previous-GTIDs=empty; binlog_event有: 1-40
bin.002 : Previous-GTIDs=1-40; binlog_event有: 41-80
bin.003 : Previous-GTIDs=1-80; binlog_event有: 81-120
bin.004 : Previous-GTIDs=1-120; binlog_event有: 121-160

假設如今咱們要找GTID=$A,那麼MySQL的掃描順序爲:
- 從最後一個binlog開始掃描(即: bin.004)
- bin.004的Previous-GTIDs=1-120,若是$A=140 > Previous-GTIDs,那麼確定在bin.004中
- bin.004的Previous-GTIDs=1-120,若是$A=88 包含在Previous-GTIDs中,那麼繼續對比上一個binlog文件 bin.003,而後再循環前面2個步驟,直到找到爲止.

======  GTID 重要參數的持久化  =======

-  GTID相關參數

-  重要參數如何持久化

1) 如何持久化gtid_executed    (前提是log-bin=mysql-bin, log_slave_update=1 )

gtid_executed = mysql.gtid_executed        #正常狀況下
或者
gtid_executed = mysql.gtid_executed + last_binlog中最後沒寫到mysql.gtid_executed中的gtid_event     #恢復狀況下

2) 如何持久化重置的gtid_purged值?

reset master; set global gtid_purged=$A:a-b;

================================================================================================
1. 因爲有可能手動設置過gtid_purged=$A:a-b, binlog.index中,last_binlog的Previous-GTIDs並不會包含$A:a-b
2. 因爲有可能手動設置過gtid_purged=$A:a-b, binlog.index中,first_binlog的Previous-GTIDs確定不會出現$A:a-b
3. 重置的gtid_purged = @@global.gtid_executed(mysql.gtid_executed:注意,考慮到這個表的更新觸發條件,因此這裏
   用@@global.gtid_executed代替) - last_binlog的Previous-GTIDs  - last_binlog全部的gtid_event
4. 下面就用 $reset_gtid_purged 來表示重置的gtid

3) 如何持久化gtid_purged  (前提是log-bin=mysql-bin, log_slave_update=1 )

gtid_purged=binlog.index:first_binlog的Previous-GTIDs + $reset_gtid_purged

======  開啓GTID的必備條件  ======  

-  MySQL 5.6 版本,在my.cnf文件中添加:

gtid_mode=on (必選)                    #開啓gtid功能
log_bin=log-bin=mysql-bin (必選)       #開啓binlog二進制日誌功能
log-slave-updates=1 (必選)             #也能夠將1寫爲on
enforce-gtid-consistency=1 (必選)      #也能夠將1寫爲on

-  MySQL 5.7或更高版本,在my.cnf文件中添加:

gtid_mode=on    (必選)
enforce-gtid-consistency=1  (必選)
log_bin=mysql-bin           (可選)    #高可用切換,最好開啓該功能
log-slave-updates=1     (可選)       #高可用切換,最好打開該功能

======  新的複製協議 COM_BINLOG_DUMP_GTID  ======

-  Slave sends to master range of identifiers of executed transactions to master
-  Master send all other transactions to slave
-  一樣的GTID不能被執行兩次,若是有一樣的GTID,會自動被skip掉。

slave1 : 將自身的UUID1:1 發送給 master,而後接收到了 UUID1:2,UUID1:3 event
slave2 : 將自身的UUID1:1,UUID1:2 發送給 master,而後接收到了UUID1:3 event

Binlog dump
最開始的時候,MySQL只支持一種binlog dump方式,也就是指定binlog filename + position,向master發送COM_BINLOG_DUMP命令。在發送dump命令的時候,咱們能夠指定flag爲BINLOG_DUMP_NON_BLOCK,這樣master在沒有可發送的binlog event以後,就會返回一個EOF package。不過一般對於slave來講,一直把鏈接掛着可能更好,這樣能更及時收到新產生的binlog event。在MySQL 5.6以後,支持了另外一種dump方式,也就是GTID dump,經過發送COM_BINLOG_DUMP_GTID命令實現,須要帶上的是相應的GTID信息.

2、GTID的工做原理

從服務器鏈接到主服務器以後,把本身執行過的GTID (Executed_Gtid_Set: 即已經執行的事務編碼)<SQL線程> 、獲取到的GTID (Retrieved_Gtid_Set: 即從庫已經接收到主庫的事務編號) <IO線程>發給主服務器,主服務器把從服務器缺乏的GTID及對應的transactions發過去補全便可。當主服務器掛掉的時候,找出同步最成功的那臺從服務器,直接把它提高爲主便可。若是硬要指定某一臺不是最新的從服務器提高爲主, 先change到同步最成功的那臺從服務器, 等把GTID所有補全了,就能夠把它提高爲主了。

GTID是MySQL 5.6的新特性,可簡化MySQL的主從切換以及Failover。GTID用於在binlog中惟一標識一個事務。當事務提交時,MySQL Server在寫binlog的時候,會先寫一個特殊的Binlog Event,類型爲GTID_Event,指定下一個事務的GTID,而後再寫事務的Binlog。主從同步時GTID_Event和事務的Binlog都會傳遞到從庫,從庫在執行的時候也是用一樣的GTID寫binlog,這樣主從同步之後,就可經過GTID肯定從庫同步到的位置了。也就是說,不管是級聯狀況,仍是一主多從狀況,均可以經過GTID自動找點兒,而無需像以前那樣經過File_name和File_position找點兒了。

簡而言之,GTID的工做流程爲:
-  master更新數據時,會在事務前產生GTID,一同記錄到binlog日誌中。
-  slave端的i/o 線程將變動的binlog,寫入到本地的relay log中。
-  sql線程從relay log中獲取GTID,而後對比slave端的binlog是否有記錄。
-  若是有記錄,說明該GTID的事務已經執行,slave會忽略。
-  若是沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
-  在解析過程當中會判斷是否有主鍵,若是沒有就用二級索引,若是沒有就用所有掃描。

3、GTID的優缺點

GTID的優勢
-  一個事務對應一個惟一ID,一個GTID在一個服務器上只會執行一次;
-  GTID是用來代替傳統複製的方法,GTID複製與普通複製模式的最大不一樣就是不須要指定二進制文件名和位置;
-  減小手工干預和下降服務故障時間,當主機掛了以後經過軟件從衆多的備機中提高一臺備機爲主機;

GTID複製是怎麼實現自動同步,自動對應位置的呢?
好比這樣一個主從架構:ServerC <-----ServerA ----> ServerB
即一個主數據庫ServerA,兩個從數據庫ServerB和ServerC

當主機ServerA 掛了以後 ,此時ServerB執行完了全部從ServerA 傳過來的事務,ServerC 延時一點。這個時候須要把 ServerB 提高爲主機 ,Server C 繼續爲備機;當ServerC 連接ServerB 以後,首先在本身的二進制文件中找到從ServerA 傳過來的最新的GTID,而後將這個GTID 發送到ServerB ,ServerB 得到這個GTID以後,就開始從這個GTID的下一個GTID開始發送事務給ServerC。這種自我尋找複製位置的模式減小事務丟失的可能性以及故障恢復的時間。

GTID的缺點(限制)
-  不支持非事務引擎;
-  不支持create table ... select 語句複製(主庫直接報錯);(原理: 會生成兩個sql, 一個是DDL建立表SQL, 一個是insert into 插入數據的sql; 因爲DDL會致使自動提交, 因此這個sql至少須要兩個GTID, 可是GTID模式下, 只能給這個sql生成一個GTID)
-  不容許一個SQL同時更新一個事務引擎表和非事務引擎表;
-  在一個複製組中,必需要求統一開啓GTID或者是關閉GTID;
-  開啓GTID須要重啓 (mysql5.7除外);
-  開啓GTID後,就再也不使用原來的傳統複製方式;
-  對於create temporary table 和 drop temporary table語句不支持;
-  不支持sql_slave_skip_counter;

======  那麼到底爲何要用GTID呢?======

1. classic replication         [傳統複製 , 運維之痛]

2. GTID replication       [GTID複製,很簡單]

3. GTID的Limitation (及應對措施)

- 不安全的事務 

設置enforce-gtid-consistency=1

- MySQL5.7 GTID crash-safe

1) 單線程複製
Non-GTID 推薦配置: 
relay_log_recovery=1
relay_log_info_repository=TABLE
master_info_repository=TABLE

GTID 推薦配置
MASTER_AUTO_POSITION=on
relay_log_recovery=0

2) 多線程複製
Non-GTID 推薦配置:
relay_log_recovery=1
sync_relay_log=1
relay_log_info_repository=TABLE
master_info_repository=TABLE

GTID 推薦配置:
MASTER_AUTO_POSITION=on
relay_log_recovery=0

======  Mysql開啓GTID時,須要注意的問題  ======

-  slave不能執行任何sql,包括超級用戶;
-  read_only=on, slave必需要開啓這個,避免業務執行sql;
-  保證當前slave的事務id爲1;

當slave同步出現問題時,手動跳過,須要考慮的問題
- 執行的sql,不能記錄事務id,不然slave切換爲master時,會致使從同步失敗,由於binglog早已刪除。
- SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
- SET @@SESSION.SQL_LOG_BIN= 0;

須要執行的sql操做:

SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;

查看當前數據的uuid

show GLOBAL VARIABLES like 'server_uuid';

查看當前數據庫的已執行過的事務

show master status;

手動設置事務id

SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
SET @@GLOBAL.GTID_PURGED='132028ab-abc5-11e6-b2f0-000c29a60c3d:1-45679';
SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;

另外還須要注意
-  開啓GTID之後,沒法使用sql_slave_skip_counter跳過事務,由於主庫會把從庫缺失的GTID,發送給從庫,因此skip是沒有用的。
-  爲了提早發現問題,在gtid模式下,直接禁止使用set global sql_slave_skip_counter =x。正確的作法: 經過set grid_next= 'aaaa'('aaaa'爲待跳過的事務),而後執行BIGIN; 接着COMMIT產生一個空事務,佔據這個GTID,再START SLAVE,會發現下一條事務的GTID已經執行過,就會跳過這個事務了
-  若是一個GTID已經執行過,再遇到重複的GTID,從庫會直接跳過,可看做GTID執行的冪等性。

4、GTID測試解析

1)  複製的測試環境
由於支持GTID,因此5.6多了幾個參數:

mysql> show 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_next                        | AUTOMATIC                                |
| gtid_owned                       |                                          |
| gtid_purged                      | d47f31fd-eba4-11e7-af2a-56b1d2e75ff8:1-9 |
| session_track_gtids              | OFF                                      |
+----------------------------------+------------------------------------------+
9 rows in set (0.00 sec)

這裏簡單說下幾個經常使用參數的做用:

gtid_executed
在當前實例上執行過的 GTID 集合,實際上包含了全部記錄到 binlog 中的事務。設置 set sql_log_bin=0 後執行的事務不會生成 binlog 事件,也不會被記錄到 gtid_executed 中。執行 RESET MASTER 能夠將該變量置空。

gtid_purged
binlog 不可能永遠駐留在服務上,須要按期進行清理(經過 expire_logs_days 能夠控制按期清理間隔),不然早晚它會把磁盤用盡。gtid_purged 用於記錄本機上已經執行過,可是已經被清除了的 binlog 事務集合。它是 gtid_executed 的子集。只有 gtid_executed 爲空時才能手動設置該變量,此時會同時更新 gtid_executed 爲和 gtid_purged 相同的值。

gtid_executed 爲空意味着要麼以前沒有啓動過基於 GTID 的複製,要麼執行過 RESET MASTER。執行 RESET MASTER 時一樣也會把 gtid_purged 置空,即始終保持 gtid_purged 是 gtid_executed 的子集。

gtid_next
會話級變量,指示如何產生下一個GTID。可能的取值以下:
-  AUTOMATIC: 自動生成下一個 GTID,實現上是分配一個當前實例上還沒有執行過的序號最小的 GTID。
-  ANONYMOUS: 設置後執行事務不會產生GTID。
-  顯式指定的GTID: 能夠指定任意形式合法的 GTID 值,但不能是當前 gtid_executed 中的已經包含的 GTID,不然下次執行事務時會報錯。

mysql5.6主從環境的搭建和5.5沒有什麼區別,惟一須要注意: 開啓GTID須要在my.cnf配置文件中啓用這三個參數(每一個節點上都添加)

#GTID
gtid_mode = on                  #開啓gtid功能
enforce_gtid_consistency = 1    #表示開啓gtid的一些安全限制,也能夠將1寫成on
log_slave_updates = 1           #注意1表示打開該功能,也能夠將1寫成on

上面任意一個參數任意一個參數不開啓則都會報錯:

2017-08-09 02:33:57 6512 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates
2017-08-09 02:33:57 6512 [ERROR] Aborting

2017-08-09 02:39:58 9860 [ERROR] --gtid-mode=ON or UPGRADE_STEP_1 requires --enforce-gtid-consistency
2017-08-09 02:39:58 9860 [ERROR] Aborting

這裏特地說下"log_slave_updates"這個參數選項,一般slave服務器從master服務器接收到的更新不記入slave的二進制日誌。該參數選項告訴slave從服務器將其SQL線程執行的更新記入到slave服務器本身的二進制日誌。爲了使該選項生效,還必須啓動binlog二進制日誌功能!!好比:

A01和A02爲主主複製,A01和B01爲主從複製,在測試的過程當中發現瞭如下問題:
-  A01和A02的主主複製是沒有問題的(從A01寫入數據能同步到A02,從A02寫入數據可以同步到A01);
-  主從同步的時候,當從A01寫入的時候,數據能夠寫入到B01;
-  當從A02寫入的時候,數據就不能寫入到B01;

這個問題產生的緣由:log_slave_updates參數的狀態爲NO

建立mysql三個實例(330六、330七、3308),啓動以後,執行change時須要注意

各個實例的uuid:

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

3307:
mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| 041d0e65-3cde-11e5-9a6e-001c4270714e |
+--------------------------------------+

3308:
mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| 081ccacf-3ce4-11e5-9a95-001c4270714e |
+--------------------------------------+

使用5.6以前的主從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

報錯:

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 參數的時候,MASTER_LOG_FILE,MASTER_LOG_POS參數不能使用。

使用5.6以後的主從change:

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

在執行上面的命令的時候會報錯2個warnings,主要的緣由是複製帳號安全的問題。

從整體上看來,因爲要支持GTID,因此不須要手工肯定主服務器的MASTER_LOG_FILE及MASTER_LOG_POS。要是不須要GTID則須要指定FILE和POS。在2個從上執行上面命令,到此主從環境搭建完成。GTID的主從完成以後能夠經過show processlist查看:

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

2) 測試複製的故障轉移

server1(3306)掛了,服務器起不來了。須要把其中的一個從設置爲主,另外一個設置爲其的從庫:

server2(3307):

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

server3(3308):

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

相比之下server2完成的事務要比server3更接近或則等於server1,如今須要把server3設置爲server2的從庫。

在MySQL5.6以前,這裏的計算會很麻煩,要計算以前主庫的log_pos和當前要設置成主庫的log_pos,頗有可能出錯。因此出現了一些高可用性的工具如MHA,MMM等解決問題。

在MySQL5.6以後,很簡單的解決了這個難題。由於同一事務的GTID在全部節點上的值一致,那麼根據server3當前中止點的GTID就能定位到server2上的GTID,因此直接在server3上執行change便可:

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

#千萬不要執行 reset master,不然會從最早的GTID上開始執行。

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)

主從結構已經變動,server2是Master,server3是Slave。由於不須要計算pos的值,因此經過GTID很簡單的解決了這個問題

3) 跳過複製錯誤:gtid_next、gtid_purged

 從服務器跳過一個錯誤的事務

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

在MySQL5.6以前,只須要執行:

mysql> set global sql_slave_skip_counter=1; 

跳過一個錯誤的事務,就能夠繼續進行復制了。但在MySQL5.6以後則不行:

mysql> set global sql_slave_skip_counter=1;
ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction

分析:由於是經過GTID來進行復制的,也須要跳過這個事務從而繼續複製,這個事務能夠到主上的binlog裏面查看:由於不知道找哪一個GTID上出錯,因此也不知道如何跳過哪一個GTID。但在show slave status裏的信息裏能夠找到在執行Master裏的POS:151

Exec_Master_Log_Pos: 151

的時候報錯,因此經過mysqlbinlog找到了GTID:

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

找到這個GTID以後執行:必須按照下面順序執行

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

mysql> set session gtid_next='4e659069-3cd8-11e5-9a49-001c4270714e:1';     #在session裏設置gtid_next,即跳過這個GTID
Query OK, 0 rows affected (0.01 sec)

mysql> begin;      #開啓一個事務
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設置回來
Query OK, 0 rows affected (0.00 sec)

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: 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.000003
                Relay_Log_Pos: 716
        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: 38260944
              Relay_Log_Space: 38261936
              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: mysql.slave_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-48
            Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-48
                Auto_Position: 1

在此成功跳過了錯誤,同步繼續。能夠經過這個辦法來處理複製失敗的問題,這裏還有個例子(從服務器中跳過一條語句/事務):

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 本來是正常的, 而後意外地執行了 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
1 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
1 ROW IN SET (0.00 sec)

slave有延遲, 雖然已經獲取到了gtid及對應的events, 可是並未執行:

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
1 ROW IN SET (0.00 sec)

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

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)

查看複製狀態
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
1 ROW IN SET (0.00 sec)

mysql > SELECT * FROM t;
+----+-------+
| id | title |
+----+-------+
|  1 | a     |
|  2 | b     |
|  3 | c     |
|  4 | d     |
+----+-------+
4 ROWS IN SET (0.00 sec)

成功跳過 truncate table, 固然此時主從的數據已經不一致了。

注意:經過GTID的複製都是沒有指定MASTER_LOG_FILE和MASTER_LOG_POS的,因此經過GTID複製都是從最早開始的事務開始,除非在本身的binlog裏面有執行過以前的記錄,纔會繼續後面的執行。

 要是事務日誌被purge,再進行change

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登錄以後執行:

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的部分,而不是在最早開始的事務執行。

在主上執行,查看被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)

在從上執行,跳過這個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)


要是出現:
ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.
則須要執行:
mysql> reset master;

到這從的同步就正常了。 

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.000003
          Read_Master_Log_Pos: 619
               Relay_Log_File: mysqld-relay-bin3308.000002
                Relay_Log_Pos: 797
        Relay_Master_Log_File: mysql-bin3306.000003
             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: 619
              Relay_Log_Space: 1006
              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:51-52
            Executed_Gtid_Set: 4e659069-3cd8-11e5-9a49-001c4270714e:1-52
                Auto_Position: 1
1 row in set (0.00 sec)

mysql> use mmm
Database changed
mysql> show tables;
+---------------+
| Tables_in_mmm |
+---------------+
| ttt           |
+---------------+
1 row in set (0.00 sec)

③ 經過另外一個從庫恢復從庫數據
好比一臺從庫誤操做,數據丟失了,能夠經過另外一個從庫來進行恢復:

slave2(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(自己實例執行的事務)
4e659069-3cd8-11e5-9a49-001c4270714e:1-46
                Auto_Position: 1

數據被誤刪除以後,最好中止複製:stop slave;

恢復數據從slave1(3307)上備份數據,並還原到slave2(3308)中。
備份:
mysqldump  -uzjy -p123456 -h127.0.0.1 -P3307 --default-character-set=utf8 --set-gtid-purged=ON -B mmm > mmm1.sql


在還原到slave2的時候須要在slave2上執行:reset master; 否則會報錯:
ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

還原:
root@zjy:~# mysql -uzjy -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)

這時候你會發現誤刪除的數據已經被還原,而且複製也正常。由於根據GTID的原理,經過slave1的備份直接能夠和Master進行同步。

這裏備份注意的一點是:在備份開啓GTID的實例裏,須要指定 --set-gtid-purged參數,不然會報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

備份文件裏面會出現:

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參數,出現GTID_PURGED直接還原的時候執行,從庫不須要其餘操做就能夠直接change到主。

                                                                順便總結一下:GTID跳過複製錯誤的方法                                                                   

1)對於跳過一個錯誤,找到沒法執行事務的編號,好比是2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10
mysql> stop slave;
mysql> set gtid_next='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-10';
mysql> begin;
mysql> commit;
mysql> set gtid_next='AUTOMATIC';
mysql> start slave;

2)上面方法只能跳過一個事務,那麼對於一批如何跳過?
在主庫執行"show master status",看主庫執行到了哪裏,好比:2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33,那麼操做以下:
mysql> stop slave;
mysql> reset master;
mysql> set global gtid_purged='2a09ee6e-645d-11e7-a96c-000c2953a1cb:1-33';
mysql> start slave;

5、運維場景中GTID的運用

======  使用GTID搭建Replication  ======

-  從0開始搭建

step 1: 讓全部server處於同一個點
mysql> SET @@global.read_only = ON;

step 2: 關閉全部MySQL
# mysqladmin -uusername -p shutdown

step 3: 重啓全部MySQL,並開啓GTID
# mysqld --gtid-mode=ON --log-bin --enforce-gtid-consistency &

固然,在my.cnf文件中配置好最佳!

step 4: 在從數據庫上經過change master語句進行復制
mysql> change master to master_host=host,master_port=port,master_user=user,master_password=password,master_auto_position=1;
mysql> start slave;

step 5: 讓master可讀可寫
mysql> SET @@global.read_only = OFF;

-  從備份中恢復&搭建

step 1: 備份
mysqldump  xx;      #獲取而且記錄gtid_purged值
or
冷備份;              #獲取而且記錄gtid_executed值,這個就至關於mysqldump中獲得的gtid_purged

step 2: 在新服務器上reset master,導入備份
mysql> reset master;         #清空gtid信息
導入備份;                     #若是是邏輯導入,請設置sql_log_bin=off
mysql> set global gtid_purged=xx;

step 3: 在從數據庫上經過change master語句進行復制
mysql> change master to master_host=host,master_port=port,master_user=user,master_password=password,master_auto_position=1;
mysql> start slave;

======  如何從classic replication 升級成 GTID replication  ====== 

-  offline 方式升級 (線下升級)

offline 的方式升級最簡單:
- 所有關閉mysql
- 在my.cnf文件中配置好GTID
- 重啓mysql
- 登陸mysql,執行"change master to MASTER_AUTO_POSITION=1;"

-  online 方式升級 (線上升級)

先介紹幾個重要GTID_MODE的參數:
GTID_MODE = OFF
不產生Normal_GTID,只接受來自master的ANONYMOUS_GTID

GTID_MODE = OFF_PERMISSIVE
不產生Normal_GTID,能夠接受來自master的ANONYMOUS_GTID & Normal_GTID

GTID_MODE = ON_PERMISSIVE
產生Normal_GTID,能夠接受來自master的ANONYMOUS_GTID & Normal_GTID

GTID_MODE = ON
產生Normal_GTID,只接受來自master的Normal_GTID

概括總結:
1)當master產生Normal_GTID的時候,若是slave的gtid_mode(OFF)不能接受Normal_GTID,那麼就會報錯
2)當master產生ANONYMOUS_GTID的時候,若是slave的gtid_mode(ON)不能接受ANONYMOUS_GTID,那麼就會報錯
3)設置auto_position的條件: 當master的gtid_mode=ON時,slave能夠爲OFF_PERMISSIVE,ON_PERMISSIVE,ON。
   除此以外,都不能設置auto_position = on

============================================
下面開始說下如何online 升級爲GTID模式?

step 1: 每臺server執行
檢查錯誤日誌,直到沒有錯誤出現,才能進行下一步
mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;

step 2: 每臺server執行
mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;

step 3: 每臺server執行
不用關心一組複製集羣的server的執行順序,只須要保證每一個Server都執行了,才能進行下一步
mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;

step 4: 每臺server執行
不用關心一組複製集羣的server的執行順序,只須要保證每一個Server都執行了,才能進行下一步
mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;

step 5: 在每臺server上執行,若是ONGOING_ANONYMOUS_TRANSACTION_COUNT=0就能夠
不須要一直爲0,只要出現過0一次,就ok
mysql> SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';

step 6: 確保全部anonymous事務傳遞到slave上了
#master上執行
mysql> SHOW MASTER STATUS;

#每一個slave上執行
mysql> SELECT MASTER_POS_WAIT(file, position);

或者,等一段時間,只要不是大的延遲,通常都沒問題

step 7: 每臺Server上執行
mysql> SET @@GLOBAL.GTID_MODE = ON;

step 8: 在每臺server上將my.cnf中添加好gtid配置
gtid_mode=on
enforce-gtid-consistency=1
log_bin=mysql-bin
log-slave-updates=1

step 9: 在從機上經過change master語句進行復制
mysql> STOP SLAVE;
mysql> CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
mysql> START SLAVE;

 ======  GTID failover (故障轉移)  ======

-  MySQL crash (Mysql 崩潰) 

配置好loss-less semi-sync replication,能夠更可靠的保證數據零丟失!下面說的都是mysql crash 後,起不來的狀況:

binlog 在master還有日誌沒有傳遞到slave (解決措施以下)

1. 選取最新的slave,change master to maseter_auto_position同步好
2. mysqlbinlog 將沒傳遞過來的binlog在新master上replay
3. 打開新master的surper_read_only=off;

binlog 已經傳遞到slave  (解決措施以下)

1. 選取最新的slave,change master to maseter_auto_position同步好
2. 打開新master的surper_read_only=off;

-  OS crash  (操做系統崩潰)

1. 選取最新的slave,change master to maseter_auto_position同步好
2. 打開新master的surper_read_only=off;

以上操做,在傳統模式複製下,須要經過MHA來實現,但MHA仍是比較複雜。如今有了GTID模式的狀況下,實現起來就很是簡單,很是方便了。

======  GTID 運維和錯誤處理  ======

使用GTID後,對原來傳統的運維有不一樣之處了,須要調整過來;使用Row模式且複製配置正確的狀況下,基本上不多發現有複製出錯的狀況;slave 設置 "super_read_only=on"

-  錯誤場景: Errant transaction

出現這種問題基本有兩種狀況
-  複製參數沒有配置正確,當slave crash後,會出現重複鍵問題;
-  DBA操做不正確,不當心在slave上執行了事務;

對於第一個重複鍵問題的解決措施:
1) 傳統模式 (須要skip transation)
SQL> SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
SQL> START SLAVE;

2) GTID模式
SQL> SET GTID_NEXT='b9b4712a-df64-11e3-b391-60672090eb04:7';   --設置須要跳過的gtid event
SQL> BEGIN;COMMIT;
SQL> SET GTID_NEXT='AUTOMATIC';
SQL> START SLAVE;

對於第二種不當心多執行了事務
這種狀況就比較難了,這樣已經致使了數據不一致,大多數狀況,建議slave重作
如何避免?  則須要在slave上設置 "super_read_only=on"

-  特別注意: 當發生inject empty transction後,有可能會丟失事務

這裏說下inject empty transction的隱患:
-  當slave上inject empty transction,說明有一個master的事務被忽略了(這裏假設是 $uuid:100)
-  事務丟失一:若是此時此刻master掛了,這個slave被選舉爲新master,那麼其餘的slave若是尚未執行到$uuid:100,就會丟失掉$uuid:100這個事務。
-  事務丟失二:若是從備份中從新搭建一個slave,須要從新執行以前的全部事務,而此時,master掛了, 又回到了事務丟失一的場景。

-  如何重置gtid_executed,gtid_purged

設置gtid_executed
mysql> reset master     #目前只能這麼操做

設置gtid_purged
- 當gtid_executed 非空的時候,不能設置gtid_purged
- 當gtid_executed 爲空的時候(即剛搭建好mysql), 能夠直接SET @@GLOBAL.GTID_PURGED='0ad6eae9-2d66-11e6-864f-ecf4bbf1f42c:1-3';

-  若是auto.cnf 被刪掉了,對於GTID的複製會有什麼影響?

若是被刪掉,重啓後,server-uuid 會變

-  手動設置"set @@gtid_purged = xx:yy", mysql會去主動修改binlog的頭麼?

不會去主動修改!

-  GTID和複製過濾規則之間如何協同工做?MySQL,test還能愉快的過濾掉嗎?

GTID和複製過濾規則之間如何協同工做?MySQL,test還能愉快的過濾掉嗎?

6、基於GTID模式的主從複製環境部署記錄 (Mysql 5.6 +GTID複製)

mysql主數據庫: 172.16.60.205 (master)
mysql從數據庫: 172.16.60.206 (slave)
mysql5.6.39 安裝部署,參考:https://www.cnblogs.com/kevingrace/p/6109679.html
 
mysql5.7+GTID複製的配置和5.6的配置基本一致~
 
============================================
主數據庫172.16.60.205的操做
 
my.cnf文件裏GTID複製的配置內容以下:
[root@mysql-master ~]# vim /usr/local/mysql/my.cnf
.........
#GTID:
server_id = 205
gtid_mode = on
enforce_gtid_consistency = on    #強制gtid一直性,用於保證啓動gitd後事務的安全;
 
#binlog
log_bin = master-bin
log-slave-updates = 1       #在從服務器進入主服務器傳入過來的修改日誌所使用,在Mysql5.7以前主從架構上使用gtid模式的話,必須使用此選項,在Mysql5.7取消了,會增長系統負載。
binlog_format = row         #推薦採用此模式
sync-master-info = 1        #同步master_info,任何事物提交之後都必需要把事務提交之後的二進制日誌事件的位置對應的文件名稱,記錄到master_info中,下次啓動自動讀取,保證數據無丟失
sync_binlog = 1             #最好加上這一行。表示binlog進行FSYNC刷盤,同時dump線程會在sync階段後進行binlog傳輸

#relay log
skip_slave_start = 1
 
配置完成以後,別忘了重啓Mysql
[root@mysql-master ~]# /etc/init.d/mysql restart
Shutting down MySQL..                                      [  OK  ]
Starting MySQL..                                           [  OK  ]
 
查看一下master狀態, 發現多了一項"Executed_Gtid_Set "
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000006 |      151 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
 
mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | b3df746a-1487-11e9-a8ba-0050568843f8 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)
 
mysql> show global variables like '%gtid%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| binlog_gtid_simple_recovery     | OFF   |
| enforce_gtid_consistency        | ON    |
| gtid_executed                   |       |
| gtid_mode                       | ON    |
| gtid_owned                      |       |
| gtid_purged                     |       |
| simplified_binlog_gtid_recovery | OFF   |
+---------------------------------+-------+
7 rows in set (0.00 sec)
 
主庫執行從庫複製受權
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.206' identified by "slave@123";
Query OK, 0 rows affected (0.01 sec)
 
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
 
mysql> show grants for slave@'172.16.60.206';   
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for slave@172.16.60.206                                                                                                                   |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'172.16.60.206' IDENTIFIED BY PASSWORD '*4F0FF134CC4C1A2872D972373A6AA86CA0A81872' |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
 
這裏須要注意一下:
啓動配置以前,一樣須要對從服務器進行初始化。對從服務器初始化的方法基本和基於日誌點是相同的,只不過在啓動了GTID模式後,在備份中所記錄的就不是備份時的二進制日誌文件名和偏移量了,
而是記錄的是備份時最後的GTID值。
 
須要先在主數據庫機器上把目標庫備份一下,假設這裏目標庫是kevin(爲了測試效果,下面手動建立)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
 
mysql> CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci;      
Query OK, 1 row affected (0.01 sec)
 
mysql> use kevin;
Database changed
mysql> create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.27 sec)
 
mysql> insert into kevin.haha values(1,"congcong"),(2,"huihui"),(3,"grace");      
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0
 
mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
+----+----------+
3 rows in set (0.00 sec)
 
把kevin庫備份出來
[root@mysql-master ~]# mysqldump --single-transaction --master-data=2 --triggers --routines --database kevin -uroot -p123456 > /root/kevin.sql
 
備份完成以後,查看一下sql文件內容。
[root@mysql-master ~]# cat /root/kevin.sql
-- MySQL dump 10.13  Distrib 5.6.39, for Linux (x86_64)
--
-- Host: localhost    Database: kevin
-- ------------------------------------------------------
-- Server version       5.6.39-log
...............
...............
--
-- GTID state at the beginning of the backup
--
 
SET @@GLOBAL.GTID_PURGED='b3df746a-1487-11e9-a8ba-0050568843f8:1-5';
 
--
...............
...............
 
而後把備份的/root/kevin.sql文件拷貝到從數據庫服務器上
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr /root/kevin.sql root@172.16.60.206:/root/
 
============================================
從數據庫172.16.60.206的操做
 
my.cnf文件裏GTID複製的配置內容以下:
與主服務器配置大概一致,除了server_id不一致外,從服務器還能夠在配置文件裏面添加:"read_only=on" ,
使從服務器只能進行讀取操做,此參數對超級用戶無效,而且不會影響從服務器的複製;
[root@mysql-slave ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 206
gtid_mode = on
enforce_gtid_consistency = on
 
#binlog
log_bin = master-bin
log-slave-updates = 1   
binlog_format = row
sync-master-info = 1
sync_binlog = 1
 
#relay log
skip_slave_start = 1     
read_only = on
 
配置完成以後,別忘了重啓Mysql
[root@mysql-slave ~]# /etc/init.d/mysql restart
Shutting down MySQL..                                      [  OK  ]
Starting MySQL..                                           [  OK  ]
 
接着將主數據庫目標庫的備份數據kevin.sql導入到從數據庫裏
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
 
mysql> source /root/kevin.sql;
 
mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
+----+----------+
3 rows in set (0.00 sec)
 
在從數據庫裏,使用change master 配置主從複製
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
 
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.50 sec)
 
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
 
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.205
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000006
          Read_Master_Log_Pos: 1270
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 411
        Relay_Master_Log_File: master-bin.000006
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..............
..............
           Retrieved_Gtid_Set:
            Executed_Gtid_Set: b3df746a-1487-11e9-a8ba-0050568843f8:1-5          #這是master主數據庫的GTID
                Auto_Position: 1
 
而後回到主數據庫中查看master狀態
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       206 |      | 3306 |       205 | b6589756-1487-11e9-a8bb-005056ac509b |
+-----------+------+------+-----------+--------------------------------------+
1 row in set (0.00 sec)
 
經過上面一系列配置,則mysql基於GTID的主從複製環境就部署好了。
 
下面開始驗證:
在172.16.60.205的主數據庫裏插入新數據
mysql> insert into kevin.haha values(10,"heifei"),(11,"huoqiu"),(12,"chengxihu");      
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0
 
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
 
到172.16.60.206的從數據庫裏查看,發現已經同步過來了
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)

若是上面slave再使用"change master to..."進行同步複製操做時報錯:Error 'Can't create database 'kevin'; database exists' on query. Default database: 'kevin'. Query: 'CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci', 則解決辦法就是把slave從庫裏導入的kevin庫刪除,而後再接着執行同步複製操做:stop slave; change master to ...; start slave 便可!

                                                   重作GTID主從複製關係 (遷移到新的slave從庫或變動slave從庫)                                                 
因爲master主數據庫上當前GTID_EXECUTED參數已經有值,而從master主庫直接備份出來的dump文件中包含了SET @@GLOBAL.GTID_PURGED的操做,因此在新的slave從數據庫導入dump備份文件時,會報錯: ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty. (這個報錯在遷移數據庫的時候頗有可能會碰過)

有兩種方法解決上面的問題(可使用其中任意一個方法,也能夠兩種方法一塊兒使用):
方法一: 執行命令"reset master",這個操做能夠將當前slave庫的GTID_EXECUTED值置空;
方法二: 在dump導出master數據時,添加--set-gtid-purged=off參數,避免將master上的gtid信息導出,而後再導入到slave庫;

在添加--set-gtid-purged=off參數前的dump導出文件信息以下(包含了SET @@GLOBAL.GTID_PURGED的操做):

在添加--set-gtid-purged=off參數後的dump導出文件信息以下:

如上是在172.16.60.205 master主庫和 172.16.60.206 slave從庫之間作的GTID複製關係, 假設如今172.16.60.206 slave節點有問題,須要將數據遷移到另外一個slave節點(好比172.16.60.207)上, 則遷移後須要從新配置GTID主從複製關係 !操做記錄以下:

1)在172.16.60.205主數據庫上的操做
mysql > reset master;
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.207' identified by "slave@123";
mysql> flush privileges;
   
[root@mysql-master ~]# mysqldump -uroot -p'123456' -B -A -F --set-gtid-purged=OFF  --master-data=2 --single-transaction  --events |gzip >/root/205_$(date +%F).sql.gz
   
/root/205_2019-01-10.sql.gz
[root@mysql-master ~]# ll /root/205_*
-rw-r--r-- 1 root root 181334 Jan 10 14:26 /root/205_2019-01-10.sql.gz
   
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr /root/205_2019-01-10.sql.gz root@172.16.60.207:/root/
   
2) 在新的slave節點172.16.60.207從數據庫上的操做
[root@mysql-slave2 ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 207
gtid_mode = on
enforce_gtid_consistency = on
    
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
    
#relay log
skip_slave_start = 1  
read_only = on
    
配置完成以後,別忘了重啓Mysql
[root@mysql-slave2 ~]# /etc/init.d/mysql restart
Shutting down MySQL..                                      [  OK  ]
Starting MySQL..                                           [  OK  ]
    
接着將主數據庫拷貝過來的備份數據導入到從數據庫中
[root@mysql-slave2 ~]# gzip -d 205_2019-01-10.sql.gz
[root@mysql-slave2 ~]# ls 205_2019-01-10.sql
205_2019-01-10.sql
   
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
    
mysql> source /root/205_2019-01-10.sql;
   
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)
   
在從數據庫裏,使用change master 配置主從複製
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
    
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.50 sec)
    
mysql> start slave;
Query OK, 0 rows affected (0.05 sec)
    
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.205
                  Master_User: slave
                  Master_Port: 3306
..............
..............
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..............
..............
           Retrieved_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-2
            Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-2,
d743d65c-14b8-11e9-a9fb-005056ac05b5:1-126
                Auto_Position: 1
1 row in set (0.00 sec)
   
經過上面可知,新添加的slave節點172.16.60.207已經和主數據庫172.16.60.205配置好了GTID主從複製關係了。
   
接着回到master數據庫查看
mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000003 |      745 |              |                  | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-4 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       206 |      | 3306 |       205 | 26ca2900-14f0-11e9-ab63-005056ac509b |
|       207 |      | 3306 |       205 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)

由上面結果可知,新節點172.16.60.207已經成爲了172.16.60.205主庫的slave,即有了主從同步關係!

在master主數據庫插入新數據
mysql> insert into kevin.haha values(20,"lanzhou"),(21,"zhongguo");
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

而後到新的slave從庫172.16.60.207上查看
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
| 20 | lanzhou   |
| 21 | zhongguo  |
+----+-----------+
8 rows in set (0.00 sec)

可是到以前的slave從庫172.16.60.206上查看,發現沒有成功同步到master主庫在上面插入的數據庫
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)

查看172.16.60.206機器上查看slave同步狀態
mysql> show slave status \G;
..........
..........
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..........
           Retrieved_Gtid_Set: 59a1b34c-14f0-11e9-ab65-0050568843f8:6
            Executed_Gtid_Set: 59a1b34c-14f0-11e9-ab65-0050568843f8:1-6
                Auto_Position: 1

發現172.16.60.206 從庫的slave同步狀態是正常的! 由於IO和SQL都是YES!
那麼爲何會同步不到master插入的新數據呢?
緣由是:由於此時172.16.60.206從庫的gtid和master主庫的gtid不同了!

mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-6 |
| gtid_mode     | ON                                       |
| gtid_owned    |                                          |
| gtid_purged   | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5 |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)

而在172.16.60.205主庫和新從庫172.16.60.207上查看的gtid,發現這兩個節點的gtid是同樣的,因此它們兩個數據能保持一致性!
可是172.16.60.206的gtid和它們兩個的gtid不同,因此172.16.60.206數據不能和master保持一致!

在172.16.60.205主庫節點上查看gtid
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-3 |
| gtid_mode     | ON                                       |
| gtid_owned    |                                          |
| gtid_purged   |                                          |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)

在172.16.60.207從庫節點上查看gtid

mysql> show global variables like 'gtid_%';
+---------------+--------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                |
+---------------+--------------------------------------------------------------------------------------+
| gtid_executed | 1e14b008-14f0-11e9-ab63-005056ac05b5:1-123,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-3 |
| gtid_mode     | ON                                                                                   |
| gtid_owned    |                                                                                      |
| gtid_purged   |                                                                                      |
+---------------+--------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

===============================================================================================================
總結: 
a) 經過以上操做方式後,新節點會成爲master主庫的slave從庫,可是可能會致使以前的slave節點的gtid跟master不同而破壞數據一致性。
b) 上面操做後,經過"show slave hosts;"查看,可能只有172.16.60.207這一個slave,以前的172.16.60.206節點的slave同步直接出現問題而致使主從複製失效。
c) 後面發如今後續添加172.16.60.208節點後(注意下面master主庫的操做),172.16.60.206的gtid又自動恢復到和master的gtid同樣了,即恢復了數據一致性的主從複製關係。

經過上面操做結果可知,採用"reset master" 以及添加"--set-gtid-purged=off"參數進行mysqldump備份,並添加新的slave節點的方式後,可能會致使以前的slave節點的主從同步失效(經過"show global variables like 'gtid_%';"命令查看以前的206從庫的gtid和master的gtid不同!)。比較推薦採用下面的方法添加新的slave,添加成功後,以前的slave的主從關係仍然保留有效,可實現"一主多從"的GTID主從複製。

                                                       一主多從的GTID主從複製                                                   
上面說到的是mysql基於GTID的一主一從模式的複製,如今須要再加一個slave從節點作成一主兩從的模式。好比追加一個新的slave從節點172.16.60.208,也做爲master主節點172.16.60.205的slave從節點,即由以前的一主一從調整爲一主兩從!

1)在master節點172.16.60.205上的操做
備份master主節點數據
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.208' identified by "slave@123";
Query OK, 0 rows affected (0.06 sec)
 
mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)
 
mysql> FLUSH TABLE WITH READ LOCK;
Query OK, 0 rows affected (0.06 sec)
 
備份master
[root@mysql-master ~]# mysqldump -u root -p'123456' --lock-all-tables --master-data=2 --flush-logs --all-databases --triggers --routines --events > 205_slave.sql
[root@mysql-master ~]# ls 205_slave.sql
205_slave.sql
 
將master的備份文件拷貝給新的slave節點172.16.60.208
[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr 205_slave.sql root@172.16.60.208:/root/
 
記錄當前的gtid
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
| gtid_mode     | ON                                       |
| gtid_owned    |                                          |
| gtid_purged   |                                          |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
 
2) 在新添加的slave節點172.16.60.208上的操做
[root@mysql-slave3 ~]# vim /usr/local/mysql/my.cnf
..........
#GTID:
server_id = 208
gtid_mode = on
enforce_gtid_consistency = on
     
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
     
#relay log
skip_slave_start = 1 
read_only = on
 
配置完成以後,別忘了重啓Mysql
[root@mysql-slave3 ~]# /etc/init.d/mysql restart
Shutting down MySQL..                                      [  OK  ]
Starting MySQL...                                          [  OK  ]
 
恢復全備
[root@mysql-slave3 ~]# ls 205_slave.sql
205_slave.sql
 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
 
mysql> source /root/205_slave.sql;
 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)
 
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
| 20 | lanzhou   |
| 21 | zhongguo  |
+----+-----------+
8 rows in set (0.00 sec)
 
 
先檢查一下新的slave節點上當前的gtid:
mysql> show global variables like 'gtid_%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
| gtid_mode     | ON                                       |
| gtid_owned    |                                          |
| gtid_purged   | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
+---------------+------------------------------------------+
4 rows in set (0.00 sec)
 
因爲新的slave庫是從master主庫恢復過來的,gtid_purged如今自動就有了值1-11,並不須要手動的執行"reset master; set global gtid_purged = 'xxxxx';",
(只有在@@global.gtid_executed爲空的狀況下,才能夠動態設置@@global.gtid_purged, 能夠經過RESET MASTER的方式來清空@@global.gtid_executed)
 
在新的slave節點上直接開啓複製就好了
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
 
mysql> change master to master_host='172.16.60.205',master_user='slave',master_password='slave@123',master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.36 sec)
 
mysql> start slave;
Query OK, 0 rows affected (0.03 sec)
 
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.205
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000007
          Read_Master_Log_Pos: 191
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 363
        Relay_Master_Log_File: master-bin.000007
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
...........
...........
           Retrieved_Gtid_Set:
            Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7
                Auto_Position: 1
1 row in set (0.00 sec)
 
ERROR:
No query specified
 
 
接着回到master數據庫查看
mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000007 |      191 |              |                  | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-7 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)
 
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       207 |      | 3306 |       205 | d743d65c-14b8-11e9-a9fb-005056ac05b5 |
|       208 |      | 3306 |       205 | 9b499047-14ca-11e9-aa6e-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
 
能夠發現,master主庫的從庫如今已經有兩個slave從節點了,新添加的172.16.60.208的slave從節點已經加進去了!
 
在master主數據庫插入新數據
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into kevin.haha values(30,"bobo"),(31,"huahua");
Query OK, 2 rows affected (0.04 sec)
Records: 2  Duplicates: 0  Warnings: 0
 
查看兩個slave從節點,發現master上新插入的數據已經同步到兩個slave從節點數據庫裏了
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
| 20 | lanzhou   |
| 21 | zhongguo  |
| 30 | bobo      |
| 31 | huahua    |
+----+-----------+
10 rows in set (0.00 sec)
 
到此,新slave節點已經成功加入到master中了,一主兩從架構也部署完成了。
另外,再追加更多slave節點,作成一主多從架構,部署方法和上面同樣。

                                                         注意上面的172.16.60.206 slave節點問題                                                                     

在上面"從新GTID主從複製"的操做中, 新節點172.16.60.207做爲新的slave從庫後,以前的slave從庫172.16.60.206的同步關係失效了!一是經過"show global variables like 'gtid_%';"命令查看gtid和master的gtid不同致使數據不能保持同步!也有可能出現下面的報錯(經過"show slave status \G;"命令查看):Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the first event '' at 4, the last event read from './master-bin.000002' at 2952, the last byte read from './master-bin.000002' at 2952.'

這個時候若是想要從新將172.16.60.206節點添加爲master主庫的slave節點,即恢復和master節點的主從複製關係,則操做方法和上面差很少,記錄以下:

1)在172.16.60.205的master主數據庫上的操做
mysql> FLUSH TABLE WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)

[root@mysql-master ~]# mysqldump -u root -p'123456' --lock-all-tables --master-data=2 --flush-logs --all-databases --triggers --routines --events > 206_slave.sql
[root@mysql-master ~]# ls 206_slave.sql 
206_slave.sql

[root@mysql-master ~]# rsync -e "ssh -p22" -avpgolr 206_slave.sql root@172.16.60.206:/root/ 

查看此時master上的GTID
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18 |
| gtid_mode     | ON                                        |
| gtid_owned    |                                           |
| gtid_purged   |                                           |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)

同時能夠在其餘兩個slave節點(172.16.60.207/208)一樣執行"show global variables like 'gtid_%';"
發現這兩個slave節點的GTID和master的GTID是同樣的!

2)在172.16.60.206的slave數據庫上的操做
[root@mysql-slave ~]# ls /root/206_slave.sql 
/root/206_slave.sql

查看此時該slave節點上的GTID
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value                                                                               |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-12,
77624378-14b9-11e9-a9ff-005056ac509b:1-4 |
| gtid_mode     | ON                                                                                  |
| gtid_owned    |                                                                                     |
| gtid_purged   |                                                                                     |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

發現此時172.16.60.206這個slave節點的GTID和master節點以及其餘兩個slave節點的GTID不同!
因此172.16.60.206不能和172.16.60.205保持主從複製關係了(即在172.16.60.206數據庫上執行"show slave status \G;"會有上面的報錯)

如今將從172.16.60.205 master主數據庫上備份過來的數據導入到172.16.60.206 slave數據庫中

mysql> source /root/206_slave.sql;

接着再次重啓slave
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.06 sec)

而後再次查看slave同步狀態
mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.205
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000009
          Read_Master_Log_Pos: 191
               Relay_Log_File: mysql-relay-bin.000006
                Relay_Log_Pos: 403
        Relay_Master_Log_File: master-bin.000009
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
.........
.........
           Retrieved_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:13-18
            Executed_Gtid_Set: 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18,
77624378-14b9-11e9-a9ff-005056ac509b:1-4
                Auto_Position: 1
1 row in set (0.00 sec)

ERROR: 
No query specified

發現172.16.60.206 slave節點已經和172.16.60.205 master節點恢復了主從複製關係。
即IO和SQL的狀態都爲YES!

再次看看172.16.60.206 slave節點的GTID,發現和master節點以及其餘兩個slave節點的GTID同樣了。
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value                                                                               |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18,
77624378-14b9-11e9-a9ff-005056ac509b:1-4 |
| gtid_mode     | ON                                                                                  |
| gtid_owned    |                                                                                     |
| gtid_purged   |                                                                                     |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

再次查看172.16.60.205 master主數據庫上
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| gtid_executed | 71fffa5a-14b9-11e9-a9ff-0050568843f8:1-18 |
| gtid_mode     | ON                                        |
| gtid_owned    |                                           |
| gtid_purged   |                                           |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)

mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       207 |      | 3306 |       205 | d743d65c-14b8-11e9-a9fb-005056ac05b5 |
|       206 |      | 3306 |       205 | 77624378-14b9-11e9-a9ff-005056ac509b |
|       208 |      | 3306 |       205 | 9b499047-14ca-11e9-aa6e-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
3 rows in set (0.00 sec)

經過上面結果可看出,172.16.60.206已經恢復了和172.16.60.205 master節點的主從複製關係了。
即172.16.60.205 master節點有三個slave節點,

如今在172.16.60.205 master節點插入新數據
mysql> insert into kevin.haha values(40,"shanghai"),(41,"beijing");      
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

在其餘三個slave節點查看,發現新數據都正常複製過去了
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
| 20 | lanzhou   |
| 21 | zhongguo  |
| 30 | bobo      |
| 31 | huahua    |
| 40 | shanghai  |
| 41 | beijing   |
+----+-----------+
12 rows in set (0.00 sec)

 舒適提示:上面這種操做也是在slave從庫出現"數據同步失敗"或"slave同步故障「時進行重作GTID主從複製的一種有效有段!!!

                                                                  GTID主從複製 故障轉移 (failover)                                                              

如今172.16.60.205爲master主庫,分別有三個slave從庫:
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       207 |      | 3306 |       205 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
|       206 |      | 3306 |       205 | 26ca2900-14f0-11e9-ab63-005056ac509b |
|       208 |      | 3306 |       205 | 2147a0ce-14f0-11e9-ab63-005056ac5b56 |
+-----------+------+------+-----------+--------------------------------------+
3 rows in set (0.00 sec)

若是如今172.16.60.205主庫發生故障,好比mysql宕了
[root@mysql-master ~]# /etc/init.d/mysql stop
Shutting down MySQL....                                    [  OK  ]
[root@mysql-master ~]# lsof -i:3306

而後在三個slave節點上經過"show slave status \G;"查看同步狀態,會出現"Slave_IO_Running: Connecting"
即此時的主從複製關係失效了!

如今要作的就是:選取最新的slave做爲master,好比選擇172.16.60.208節點做爲master主庫。
操做以下:

172.16.60.208節點上打開讀寫功能,即surper_read_only=off
[root@mysql-slave3 ~]# vim /usr/local/mysql/my.cnf 
........
#read_only = on

[root@mysql-slave3 ~]# /etc/init.d/mysql restart   
Shutting down MySQL..                                      [  OK  ]
Starting MySQL..                                           [  OK  ]

mysql> show variables like '%read_only%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_read_only | OFF   |
| read_only        | OFF   |
| tx_read_only     | OFF   |
+------------------+-------+
3 rows in set (0.00 sec)

mysql> grant replication slave,replication client on *.* to slave@'172.16.60.206' identified by "slave@123"; 
Query OK, 0 rows affected (0.15 sec)

mysql> grant replication slave,replication client on *.* to slave@'172.16.60.207' identified by "slave@123"; 
Query OK, 0 rows affected (0.04 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)


查看gtid
mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| gtid_executed | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode     | ON                                        |
| gtid_owned    |                                           |
| gtid_purged   | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-9  |
+---------------+-------------------------------------------+
4 rows in set (0.00 sec)

而後在172.16.60.206/207兩個slave節點上執行下面命令,即以172.16.60.208爲master的同步複製關係:
mysql> stop slave;
Query OK, 0 rows affected (0.17 sec)

mysql> change master to master_host='172.16.60.208',master_user='slave',master_password='slave@123',master_auto_position=1; 
Query OK, 0 rows affected, 2 warnings (0.18 sec)

mysql> start slave;
Query OK, 0 rows affected (0.05 sec)

mysql> show slave status \G;
...............
...............
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
...............
...............
           Retrieved_Gtid_Set: 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3
            Executed_Gtid_Set: 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12
                Auto_Position: 1

 分別查看172.16.60.206/207兩個slave節點的gtid
 mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value                                                                               |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode     | ON                                                                                  |
| gtid_owned    |                                                                                     |
| gtid_purged   | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5                                            |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

mysql> show global variables like 'gtid_%';
+---------------+-------------------------------------------------------------------------------------+
| Variable_name | Value                                                                               |
+---------------+-------------------------------------------------------------------------------------+
| gtid_executed | 2147a0ce-14f0-11e9-ab63-005056ac5b56:1-3,
59a1b34c-14f0-11e9-ab65-0050568843f8:1-12 |
| gtid_mode     | ON                                                                                  |
| gtid_owned    |                                                                                     |
| gtid_purged   | 59a1b34c-14f0-11e9-ab65-0050568843f8:1-5                                            |
+---------------+-------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

由上面可看出,172.16.60.206/207兩個slave節點的gtid和172.16.60.208節點的gtid是同樣的,由於他們的數據會保持一致性同步!

在172.16.60.208節點上查看,發現172.16.60.206/207已經成爲了它的兩個slave從庫!
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       206 |      | 3306 |       208 | 26ca2900-14f0-11e9-ab63-005056ac509b |
|       207 |      | 3306 |       208 | 1e14b008-14f0-11e9-ab63-005056ac05b5 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)

因而可知,當以前的master主庫172.16.60.205發生故障後,選取其中的一個slave從庫172.16.60.208爲新的master主庫,
而後其他的slave從庫以這個選出來的節點做爲主庫!

在172.16.60.208主庫上插入新數據
mysql> insert into kevin.haha values(200,"haoshen"),(201,"haoren");       
Query OK, 2 rows affected (0.15 sec)
Records: 2  Duplicates: 0  Warnings: 0

而後在172.16.60.206/207從庫節點上查看,發現新數據已經同步過來了!
mysql> select * from kevin.haha;
+-----+-----------+
| id  | name      |
+-----+-----------+
|   1 | congcong  |
|   2 | huihui    |
|   3 | grace     |
|  10 | heifei    |
|  11 | huoqiu    |
|  12 | chengxihu |
|  20 | lanzhou   |
|  21 | zhongguo  |
|  30 | bobo      |
|  31 | huahua    |
|  40 | shanghai  |
|  41 | beijing   |
| 200 | haoshen   |
| 201 | haoren    |
+-----+-----------+
14 rows in set (0.00 sec)

特別注意:
1) 同一組主從複製節點的GTID必定要保持一致!(經過"show global variables like 'gtid_%';"命令查看),不然slave從庫的數據就不會和master主庫數據保持一致!
2) Mysql基於GTID還能夠作主主同步, 即雙方相互授予同步複製權限給對方, 而且設置讀寫權限 (#read_only=on, 即註釋掉只讀配置, 這個只是限制非super用戶, 對於具備super權限的用戶來講限制不來), 而後雙方相互執"stop slave", "change master to......", "start slave"同步操做便可實現主主同步.
3) 生產環境中, 能夠作多主多從, 好比"兩主三從", 兩主經過keepalived對外提供統一的出口ip, 負責寫操做; 三個從節點負責讀操做, 並經過LVS進行讀操做的負載均衡, (從節點跟主節點的vip作主從同步);
4) 主從能夠經過腳本進行自動切換. 下面是測試中使用的一個主從自動切換的腳本:

下面腳本中:
1) 172.16.60.211是主節點, 主節點的my.cnf文件中提早配置好"# read_only=on" (先註釋掉, 爲了配置自動切換的腳本 );
2) 172.16.60.212是從節點; 從節點也要提早給主節點授予同步複製的權限 (由於主節點故障恢復後, 會自動變爲新的從節點, 須要進行主從同步操做)
3) 主從節點各自安裝和配置keepalived;
3) 172.16.60.94 是VIP地址;
 
腳本內容以下:
172.16.60.211的主節點操做以下
[root@mysql-master01 ~]# mkdir -p /home/mysql
[root@mysql-master01 ~]# touch /home/mysql/remove_slave.log
[root@mysql-master01 ~]# vim /home/mysql/remove_slave.sh
#!/bin/bash
     
user=root
password=123456
log=/home/mysql/remove_slave.log
    
/usr/bin/mysql -u$user -p$password -e "show databases" >/dev/null 2>&1
a=$?
/usr/sbin/ip addr|grep 172.16.60.94
b=$?
    
if  [ $a -eq 0 -a $b -eq 0 ];then
    \cp -f /etc/my.cnf /etc/my_monit.cnf
    /bin/sed -i 's/^'read_only'/'#read_only'/g' /etc/my.cnf              
   diff /etc/my.cnf /etc/my_monit.cnf  
   c=$?
   if [ $c -ne 0 ]; then
      echo -e "\n$(date) \n172.16.60.211 機器以前是mysql從節點,可是如今變成了mysql主節點" >> $log
      systemctl restart mysqld
      mysql -u$user -p$password -e "stop slave;"  >/dev/null 2>&1
   else
     echo -e "\n$(date) \n172.16.60.211 機器如今是mysql主節點" >> $log
   fi
    
    
else
   \cp -f /etc/my.cnf /etc/my_monit.cnf
   /bin/sed -i 's/^'#read_only'/'read_only'/g' /etc/my.cnf             
   diff /etc/my.cnf /etc/my_monit.cnf  
   d=$?
   if [ $d -ne 0 ]; then
      echo -e "\n$(date) \n172.16.60.211 機器以前是mysql主節點,可是如今變成了mysql從節點" >> $log
      systemctl restart mysqld
      mysql -u$user -p$password -e "stop slave;"  >/dev/null 2>&1
      mysql -u$user -p$password -e " change master to master_host='172.16.60.212',master_user='slave',master_password='slave@123',master_auto_position=1;"  >/dev/null 2>&1
      mysql -u$user -p$password -e "start slave;"  >/dev/null 2>&1
   else
     echo -e "\n$(date) \n172.16.60.211 機器如今是mysql從節點" >> $log
   fi
fi
 
===================================================================
172.16.60.212的從節點操做以下:
[root@mysql-master01 ~]# mkdir -p /home/mysql
[root@mysql-master01 ~]# touch /home/mysql/remove_slave.log
[root@mysql-master01 ~]# vim /home/mysql/remove_slave.sh
#!/bin/bash
     
user=root
password=123456
log=/home/mysql/remove_slave.log
    
/usr/bin/mysql -u$user -p$password -e "show databases" >/dev/null 2>&1
a=$?
/usr/sbin/ip addr|grep 172.16.60.94
b=$?
    
if  [ $a -eq 0 -a $b -eq 0 ];then
    \cp -f /etc/my.cnf /etc/my_monit.cnf
    /bin/sed -i 's/^'read_only'/'#read_only'/g' /etc/my.cnf              
   diff /etc/my.cnf /etc/my_monit.cnf  
   c=$?
   if [ $c -ne 0 ]; then
      echo -e "\n$(date) \n172.16.60.212 機器以前是mysql從節點,可是如今變成了mysql主節點" >> $log
      systemctl restart mysqld
      mysql -u$user -p$password -e "stop slave;"  >/dev/null 2>&1
   else
     echo -e "\n$(date) \n172.16.60.212 機器如今是mysql主節點" >> $log
   fi
    
    
else
   \cp -f /etc/my.cnf /etc/my_monit.cnf
   /bin/sed -i 's/^'#read_only'/'read_only'/g' /etc/my.cnf             
   diff /etc/my.cnf /etc/my_monit.cnf  
   d=$?
   if [ $d -ne 0 ]; then
      echo -e "\n$(date) \n172.16.60.212 機器以前是mysql主節點,可是如今變成了mysql從節點" >> $log
      systemctl restart mysqld
      mysql -u$user -p$password -e "stop slave;"  >/dev/null 2>&1
      mysql -u$user -p$password -e " change master to master_host='172.16.60.211',master_user='slave',master_password='slave@123',master_auto_position=1;"  >/dev/null 2>&1
      mysql -u$user -p$password -e "start slave;"  >/dev/null 2>&1
   else
     echo -e "\n$(date) \n172.16.60.212 機器如今是mysql從節點" >> $log
   fi
fi
相關文章
相關標籤/搜索