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)
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)
報錯:
解決辦法:在主庫上找到更新前的資料,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
注意: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)
解決辦法:跳過該事務
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)
解決辦法:
登入主庫執行,檢視被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也從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
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表
登入主庫檢視校驗表:
this_crc: 13fa7d9d #從的校驗值 this_cnt: 4 #從的行數
master_crc: aa7a56c3 #主的校驗值 master_cnt: 5 #主的行數
登入從庫檢視校驗表:
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);