MySQL 5.6版本開啟GTID模式,必須打開參數log_slave_updates,
簡單來說就是必須在從機上再記錄一份二進制日志。這樣的無論對性能還是存儲的開銷,無疑會相應的增大
而MySQL 5.7版本開始無需在GTID模式下啟用參數log_slave_updates,其中最重要的原因在於5.7在mysql庫下引入了新的表gtid_executed,其表結構如下所示:
mysql> SHOW CREATE TABLE mysql.gtid_executed\G
*************************** 1. row ***************************
Table: gtid_executed
Create Table: CREATE TABLE `gtid_executed` (
`source_uuid` char(36) NOT NULL COMMENT 'uuid of the source where the transaction was originally executed.',
`interval_start` bigint(20) NOT NULL COMMENT 'First number of interval.',
`interval_end` bigint(20) NOT NULL COMMENT 'Last number of interval.',
PRIMARY KEY (`source_uuid`,`interval_start`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0
1 row in set (0.00 sec)
簡單來說,該表會記錄當前執行的GTID。列source對應UUID,列interval_start/interval_end表示的是事務號。在MySQL 5.6中必須配置參數log_slave_updates的最重要原因在於當slave重啟后,無法得知當前slave已經運行到的GTID位置,因為變量gtid_executed是一個內存值:
mysql> select @@global.gtid_executed\G
*************************** 1. row ***************************
@@global.gtid_executed: 7af7d3ea-933b-11e5-9da7-fa163e30f9a2:1-72054
1 row in set (0.00 sec)
所以MySQL 5.6的處理方法就是啟動時掃描最后一個二進制日志,獲取當前執行到的GTID位置信息。當然,如果DBA不小心將二進制日志刪除了,那么這又會帶來災難性的問題。
因此,MySQL 5.7將gtid_executed這個值給持久化了。采用的技巧與MySQL 5.6處理SQL thread保存位置的方式一樣,即將GTID值持久化保存在一張InnoDB表中,並與用戶事務一起進行提交,從而實現數據的一致性:
START TRANSACTION;
# user statement
......
INSERT INTO mysql.gtid_executed VALUES (...)
END;
一致不明白上面幾句話是怎么意思,今天在 MYSQL 5.7 版本中 把master.info relay-log.info 以及相應的二進制文件都刪掉,中繼日志文件刪掉,mysql重起,看 slave1的 show master status是否受影響,
發現不受影響,start slave 正常從原來的執行事物點上執行, 但在slave1執行 reset master,會清空mysql.gtid_executed 表,說明已經持久化了,MySQL 5.6 版本my.cnf log_slave_updates用於當mysql重起,由於mysql.gtid_executed 在內存沒有持久化,重起變量值會清空,MySQL 5.6的處理方法就是啟動時掃描最后一個二進制日志,獲取當前執行到的GTID位置信息,這樣做的壞處是多寫一份二進制日志,增加IO成本
若從MySQL服務器啟用了二進制日志,則表mysql.gtid_executed的更新僅在二進制rotation時發生,因為發生重啟等情況依舊可以通過掃描二進制日志判斷得知當前運行的GTID位置。
