天天看點

gtid主從複制原理和報錯解決

IP 版本 節點
10.10.10.100 centos7.2 + mysql5.6 master
10.10.10.200 slave

二、GTID的組成部分:

前面是server_uuid:後面是一個序列号

UUID:每個mysql執行個體的唯一ID,由于會傳遞到slave,是以也可以了解為源ID。

Sequence number:在每台MySQL伺服器上都是從1開始自增長的序列,一個數值對應一個事務。

三、GTID比傳統複制的優勢:

1、更簡單的實作failover,不用以前那樣在需要找log_file和log_Pos。

2、更簡單的搭建主從複制。

3、比傳統複制更加安全。

4、GTID是連續沒有空洞的,是以主從庫出現資料沖突時,可以用添加空事物的方式進行跳過。

5、多線程複制

四、GTID的工作原理:

1、master更新資料時,會在事務前産生GTID,一同記錄到binlog日志中。

2、slave端的i/o 線程将變更的binlog,寫入到本地的relay log中。

3、sql線程從relay log中擷取GTID,然後對比slave端的binlog是否有記錄。

4、如果有記錄,說明該GTID的事務已經執行,slave會忽略。

5、如果沒有記錄,slave就會從relay log中執行該GTID的事務,并記錄到binlog。

6、在解析過程中會判斷是否有主鍵,如果沒有就用二級索引,如果沒有就用全部掃描。

五、相關變量

GTID_PURGED :已經執行完被删除的binlog的事務,它是GTID_EXECUTED的子集,從MySQL5.6.9開始,該變量無法被設定。

GTID_OWNED : 表示正在執行的事務的gtid以及對應的線程ID。

GTID_EXECUTED: 表示已經在該執行個體上執行過的事務; 執行RESET MASTER 會将該變量置空; 我們還可以通過設定GTID_NEXT執行一個空事務,來影響GTID_EXECUTED

GTID_NEXT: 是SESSION級别變量,表示下一個将被使用的GTID

在記憶體中也維護了與GTID_PURGED, GTID_OWNED, GTID_EXECUTED相對應的全局對象gtid_state。

gtid_state中維護了三個集合,其中logged_gtids對應GTID_EXECUTED, lost_gtids對應GTID_PURGED,owned_gtids對應GTID_OWNED

六、要點

slave在接受master的binlog時,會校驗master的GTID是否已經執行過(一個伺服器隻能執行一次)。為了保證主從資料的一緻性,多線程隻能同時執行一個GTID。

七,GTID主從複制搭建:

1,兩台機器各自安裝好mysql

2,兩台伺服器各自安裝好mysql,修改root密碼,啟動mysql資料庫

在主庫上導出資料:

mysql> flush tables with read lock;               
# mysqldump -uroot -p --default-character-set=utf8  --single-transaction --flush-logs --set-gtid-purged=OFF  wbdb > /tmp/wbdb.sql      
mysql> unlock tables;             
# mysql -uroot -p  --default-character-set=utf8 < database.sql                                  

3,配置my.cnf參數,加入以下項目:

主:

server-id       = 1
log-bin=mysql-bin
binlog_format=row    
#當設定隔離級别為READ-COMMITED必須設定二進制日志格式為ROW
#添加以下這些選項
log-slave-updates=true           #slave更新是否記入日志
lower_case_table_names =1        #大小寫不敏感
gtid-mode=on                 # 啟用gtid類型,否則就是普通的複制架構
enforce-gtid-consistency=true     #強制GTID的一緻性
master-info-repository=TABLE     #主服資訊記錄庫=表/檔案
relay-log-info-repository=TABLE    #中繼日志資訊記錄庫
sync-master-info=1                #同步主庫資訊
slave-parallel-workers=4            #從伺服器的SQL線程數,要複制庫數目相同
binlog-checksum=CRC32            #校驗碼
master-verify-checksum=1          #主服校驗
slave-sql-verify-checksum=1        #從服校驗           

從:

server-id       = 2
log-bin=mysql-bin
binlog_format=row
log-slave-updates=true    
lower_case_table_names =1    
gtid-mode=on    
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
binlog-checksum=CRC32
slave-parallel-workers=4
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
replicate-do-db=jaat                  // 設定需要複制的資料庫(多資料庫使用逗号,隔開)           

4,登入master伺服器:

# mysql -uroot -p123456 -e "show global variables like '%uuid%';"
+---------------+--------------------------------------+
|Variable_name | Value                                |
+---------------+--------------------------------------+
|server_uuid   |3eda76df-e355-11e3-8d42-000c294698bf |
+---------------+--------------------------------------+
mysql>grant replication slave on *.* to replyuser@'10.10.10.%'identified by 'replypass';        
mysql>flush privileges;           

登入slave伺服器:

# mysql -e "show global variables like '%uuid%';"
+---------------+--------------------------------------+
|Variable_name | Value                                |
+---------------+--------------------------------------+
|server_uuid   |08c840ad-e35c-11e3-8d6f-000c29ed6c68 |
+---------------+--------------------------------------+
mysql>change master to master_host='10.10.10.100', master_user='replyuser',master_password='replypass', master_auto_position=1;
mysql>start slave;           

八,GTID事務常見報錯:(參考文檔:MySQL GTID 錯誤處理彙總)

主庫新增記錄,從庫提示主鍵沖突

主庫對象可更新,從庫無對應的對象可更新

主庫對象可删除,從庫無對應的對象可删除

主庫日志被purged的情形(即在主庫執行了reset master)

1,從庫報主鍵沖突:(Errno: 1062)

gtid主從複制原理和報錯解決

Retrieved_Gtid_Set項:記錄了relay日志從Master擷取了binlog日志的位置

Executed_Gtid_Set項:記錄本機執行的binlog日志位置(如果是從機,包括Master的binlog日志位置和slave本身的binlog日志位置)

解決辦法:在從庫上删除重複的記錄

mysql> stop slave;
mysql> delete from jaat.test where id=2;
mysql> start slave;
mysql> show slave status\G;           

2,主庫對象可更新,從庫無對應的對象可更新(Errno: 1032)

報錯:

gtid主從複制原理和報錯解決

解決辦法:在主庫上找到更新前的資料,insert到從庫裡去:

根據上面報錯是在mysql-bin.000001 日志檔案的2502位置處發生的錯誤,在主庫上找到2502位置對應的sql語句:

[root@master bin]# /usr/local/mysql/bin/mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS /data/mysql-bin.000001  |grep -A '10' 2502           
gtid主從複制原理和報錯解決

注意:where後面的部分為更新前的資料,set部分為更新後的資料,@1表示第一個列,@2表示第二列。是以可以将更新前的資料插入到從庫,在從庫上執行:

slave> stop slave sql_thread;;
slave> insert into jaat.test values(2,'mm')
slave> start slave sql_thread;           

3,主庫對象可删除,從庫無對應的對象可删除(Errno: 1032)

gtid主從複制原理和報錯解決

解決辦法:跳過該事務

mysql> stop slave sql_thread;
mysql> set gtid_next='0dbdf52e-0b1e-11e7-a0af-000c29df5573:9';                ////在執行GTID(Executed_Gtid_Set)為7(0dbdf52e-0b1e-11e7-a0af-000c29df5573:1-8)的事物報錯,是以跳過這個事物執行GTID為9的事物。
mysql> begin;commit;
mysql> set gtid_next='AUTOMATIC';
mysql> start slave sql_thread;           

4,主庫日志被purged的情形(即在主庫執行了purge binary logs to 'mysql-bin.xxxx';)(error 1236)

gtid主從複制原理和報錯解決

解決辦法:

登入主庫執行,檢視被purge的gtid(已經執行完被删除的binlog的事務):

master> show variables like '%gtid_purged%';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_purged   | 0dbdf52e-0b1e-11e7-a0af-000c29df5573:1-5 |
+---------------+------------------------------------------+
1 row in set (0.00 sec)

登入從庫執行:
mysql> stop slave;
mysql> reset mater;
mysql> set global gtid_purged = '0dbdf52e-0b1e-11e7-a0af-000c29df5573:1-5';        //這個是上面主庫查出來的值告訴SLAVE要主動抛棄掉 MASTER 上傳輸過來的1-5區間的事務,也就是在 GTID 從6開始,又會繼續應用 RELAY LOG 了。
mysql> start slave;
mysql> show slave status\G;           

如果後面有主鍵重複的報錯,删除對應的重複記錄,然後重新開機啟動主庫檢視即可(是由于我們在從庫停止期間delete這個事務沒有被從庫的relay log接受到,其次主從的binlog又被purged,而且從庫啟動後,執行了gtid_purged,是以主庫上新增的記錄在從庫上提示主鍵重複)。

注意:事實上,主從的資料已經不一緻了,應根據實際的需要考慮是否進行相應的修複

5,主庫執行了reset master指令後插入了新資料(error 1236)

gtid主從複制原理和報錯解決

解決辦法: 重新搭建從庫,讓從庫的gtid也從1開始,最後用pt工具修複不一緻。

mysql> stop slave;
mysql> reset slave all;
mysql> reset master;
mysql> change master to master_host='192.168.225.128', master_user='replyuser',master_password='replypass', master_auto_position=1;
mysql> start slave;
mysql> show slave status\G;           

6,終極解決辦法:忽略所有報錯,直到同步成功後,用pt工具進行資料校驗和修複

在主庫上執行以下操作,pt工具會根據主庫中的複制關系自動去找從庫:

[root@master ~]# pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=jaat.checksum --databases=jaat --tables=test h=192.168.225.128,u=root,p=123456 --empty-replicate-table --create-replicate-table           
gtid主從複制原理和報錯解決

DIFFS :0表示一緻,1表示不一緻。當指定--no-replicate-check時,會一直為0,當指定--replicate-check-only會顯示不同的資訊。

SKIPPED :由于錯誤或警告或過大,則跳過塊的數目。

參數意義:

--nocheck-replication-filters :不檢查複制過濾器,建議啟用。後面可以用--databases來指定需要檢查的資料庫。

--no-check-binlog-format : 不檢查複制的binlog模式,要是binlog為row模式下必須要加上該項。

--replicate-check-only : 隻顯示不同步的資訊。

--replicate= :把checksum的資訊寫入到指定表中,該執行個體中是寫入到(jaat.checksum表中)

--databases= :指定需要被檢查的資料庫,多個則用逗号隔開。

--tables= :指定需要被檢查的表,多個用逗号隔開

--empty-replicate-table : 清空checksum這個表

--create-replicate-table: 建立checksum表

登入主庫檢視校驗表:

gtid主從複制原理和報錯解決

this_crc: 13fa7d9d #從的校驗值 this_cnt: 4 #從的行數

master_crc: aa7a56c3 #主的校驗值 master_cnt: 5 #主的行數

登入從庫檢視校驗表:

gtid主從複制原理和報錯解決

pt-table-sync修複從庫不一緻的資料:他可以同步單個表,也可以同步整個庫。它不同步表結構、索引、或任何其他模式對象。是以在修複一緻性之前需要保證他們表存在。以下所有操作都要在主庫上進行:

對從庫資料的修複通常是在主庫執行sql來同步到從庫。是以,在有多個從庫時,修複某個從庫的資料實際會把修複語句同步到所有從庫。

1,在主庫上執行以下操作,pt工具會根據主庫中的複制關系自動去找從庫:(--tables和--databases參數可以不要,如果加上了這兩個參數,下面同步會自動同步單個庫的單個或者多個表,不加這兩個參數,下面的pt-table-sync表示同步所有資料)
[root@master ~]# pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=jaat.checksum --databases=jaat --tables=test h=192.168.225.128,u=root,p=123456 --empty-replicate-table --create-replicate-table           
2,列印出不同的資料,先寫master的ip,再寫slave的ip:
[root@master ~]# pt-table-sync --print --replicate=jaat.checksum h=192.168.225.128,u=root,p=123456,P=3306 h=192.168.225.129,u=root,p=123456,P=3306               

--replicate= :指定通過pt-table-checksum得到的表,這2個工具差不多都會一直用。

--databases= : 指定執行同步的資料庫,多個用逗号隔開。

3,開始同步資料:
[root@master ~]# pt-table-sync --replicate=jaat.checksums h=192.168.225.128,u=root,p=123456,P=3306 h=192.168.225.129,u=root,p=123456,P=3306 --execute                     
4,同步完成後再進行校驗:
[root@master ~]# pt-table-checksum --nocheck-replication-filters --no-check-binlog-format --replicate=jaat.checksum --databases=jaat --tables=test h=192.168.225.128,u=root,p=123456 --empty-replicate-table --create-replicate-table                    
5,驗證校驗結果,執行以下語句若傳回為空則說明修複成功:
select * from wbdb.checksum where master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc);