MySQL 在線開啟GTID的每個階段是要做什么
基本概述
我們知道MySQL有2種方式指定復制同步的方式,分別為:
- 基於binlog文件名及位點的指定方式
- 匿名事務(Anonymous_gtid_log_event)- 基於GTID(全局事務ID)的指定方式
- GTID事務(Gtid_log_event)
而基於GTID的方式在一主多從的架構下主從切換有着明顯優勢外,對於日常復制異常的故障診斷也更為方便,從個人角度而言,我也更傾向於大家做在線開啟或關閉GTID的操作,一方面該操作能盡可能小的影響數據庫停機時間,另一方面在開啟或關閉的過程中也順便可以驗證該參數的調整是否會對應用造成影響,從MySQL 5.7.6之后便開始支持動態開啟和關閉GTID模式,其參數GTID_MODE有以下取值
- OFF - 只允許匿名事務被復制同步
- OFF_PERMISSIVE - 新產生的事務都是匿名事務,但也允許有GTID事務被復制同步
- ON_PERMISSIVE - 新產生的都是GTID事務,但也允許有匿名事務被復制同步
- ON - 只允許GTID事務被復制同步
其實從該參數的幾個取值我們就能看出,在線修改是循序漸進的將匿名事務轉化為GTID事務過程(反之也一樣),我們先看看在線開啟GTID分別要做哪些事
在線開啟GTID
1. 設置GTID校驗ENFORCE_GTID_CONSISTENCY為WARN
該操作的目的是允許在主庫執行的SQL語句違反GTID一致性校驗,且只在主庫的錯誤日志中輸出warning級別日志以作提醒,我們知道GTID復制還是有一些限制條件的,其實這里就是為了考慮如果復制方式直接改為GTID模式后應用程序因為GTID的一些限制導致異常報錯,這樣做的好處是當我需要開啟GTID前,我可以把ENFORCE_GTID_CONSISTENCY參數開成WARN觀測一段時間,比如一天,如果觀測周期內在錯誤日志中並沒有發現相關的Warning信息,那我們再考慮正式開啟GTID的操作
- 示例:使用
CREATE TABLE AS SELECT
語法在GTID模式下不支持(題外話:CTAS語法在8.0.21以后GTID模式下也是支持的,該語法變更為了一個特殊的原子性DDL操作),而ENFORCE_GTID_CONSISTENCY設置為WARN時,只會在錯誤日志提示,不會直接報錯,
## 該操作在主從庫均執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
2. 設置GTID校驗ENFORCE_GTID_CONSISTENCY為ON
確認上一個步驟未在錯誤日志中出現相關Warning信息后,正式開啟GTID一致性校驗,當設置為ON后,如果再執行CREATE TABLE AS SELECT語句則會直接報錯
## 該操作在主從庫均執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
3. 設置GTID_MODE為OFF_PERMISSIVE
如前面的值描述,該操作表示新產生的事務依舊是匿名事務,但也允許有GTID事務被復制同步,對於在線開啟GTID模式而言,該步驟就是一個單純的過渡屬性(注意是為在線關閉GTID准備的),執行完后可快速到下一個階段
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
4. 設置GTID_MODE為ON_PERMISSIVE
該操作依舊是一個過渡屬性,其表示的則是新產生的都是GTID事務,但也允許有匿名事務被復制,從這個階段開始就已經是一個正式轉化的過程,但依舊是對兩種事務做兼容.
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
5. (關鍵點)確保匿名事務回放完畢
該步驟的目的是確保在正式轉換為完整的GTID模式前,老的匿名事務均以被回放完畢,確保GTID_MODE設置為ON時,不會因為殘留的匿名事務導致復制同步報錯,有以下2種方式進行校驗
## 該操作僅在從庫執行即可
## 方式1:確保該狀態值輸出的匿名事務數顯示為0(注意:只要出現過0即可表示已經轉換完成,即使后續該狀態值從0變為了大於0的值也不影響)
SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
## 在從庫上多次執行該語句
## 方式2: 查詢該視圖中LAST_SEEN_TRANSACTION可以觀測當前同步的事務是否還存在ANONYMOUS事務
select * from performance_schema.replication_applier_status_by_worker;
確保匿名事務數為0
確保回放線程回放的事務都已是GTID事務
6. 觸發一輪日志切換FLUSH LOGS
該操作的目的是為了在主庫觸發binlog的輪換,使新生成的binlog都是包含GTID的事務(防止一個binlog中包含2種類型的事務日志)
## 該操作僅在主庫執行即可
FLUSH LOGS;
7. 正式開啟GTID_MODE為ON
正式開啟GTID
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = ON;
SELECT @@GTID_MODE,@@ENFORCE_GTID_CONSISTENCY;
8. 修改配置文件確保GTID參數持久化
在my.cnf配置文件中增加GTID參數,確保重啟不會失效,該操作也可在第一步進行
## 該操作在主從庫均執行
gtid-mode = ON
enforce-gtid-consistency = 1
9. 修改復制模式為GTID方式
在開啟GTID模式后我們也要將將復制模式從基於POS點改為基於GTID,操作比較簡單
## 停止復制
STOP SLAVE;
## 修改為GTID模式
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
## 開啟復制
START SLAVE;
## 觀測復制同步狀態
SHOW SLAVE STATUS\G
在線關閉GTID
在線關閉的方式基本就類似於在線開啟GTID的逆向操作,以下只寫出步驟和具體命令,不做詳細解釋
- 先將GTID模式的復制改為基於POS點的復制
- 設置GTID_MODE為ON_PERMISSIVE
- 設置GTID_MODE為OFF_PERMISSIVE
- 觀測GTID_OWNED狀態變量變為空值及replication_applier_status_by_worker表中事務均轉為匿名事務
- 觸發FLUSH LOGS
- 設置GTID_MODE為OFF
- 設置ENFORCE_GTID_CONSISTENCY為OFF
- 修改my.cnf配置文件中GTID相關參數為OFF
1. 將復制改為基於POS點方式
stop slave;
show slave status\G
## 取show slave status\G中的Relay_Master_Log_File和Exec_Master_Log_Pos填入
## 這里一定不要漏掉MASTER_AUTO_POSITION = 0這個配置
CHANGE MASTER TO
MASTER_AUTO_POSITION = 0,
MASTER_LOG_FILE='mysql-bin.000017',
MASTER_LOG_POS=224126137;
start slave;
show slave status\G
2. 設置GTID_MODE為ON_PERMISSIVE
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
3. 設置GTID_MODE為OFF_PERMISSIVE
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
4. (關鍵點)確保GTID事務回放完畢
觀測GTID_OWNED狀態變量變為空值及replication_applier_status_by_worker表中事務均轉為匿名事務
## 該操作在從庫執行即可
SELECT @@GLOBAL.GTID_OWNED;
select * from performance_schema.replication_applier_status_by_worker;
5. 觸發FLUSH LOGS
## 該操作在主庫執行即可
FLUSH LOGS;
6. 設置GTID_MODE為OFF
## 該操作在主從庫均執行
SET @@GLOBAL.GTID_MODE = OFF;
7. 設置ENFORCE_GTID_CONSISTENCY為OFF
## 該操作在主從庫均執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = OFF;
8. 修改my.cnf配置文件中GTID相關參數為OFF
## 該操作在主從庫均執行
gtid-mode = OFF
enforce-gtid-consistency = 1
命令簡版
1. 在線開啟GTID
自行判斷命令在主庫還是從庫執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
select * from performance_schema.replication_applier_status_by_worker;
FLUSH LOGS;
SET @@GLOBAL.GTID_MODE = ON;
## 配置文件修改
gtid-mode = ON
enforce-gtid-consistency = 1
## 將復制模式從基於POS點改為基於GTID
STOP SLAVE;
CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
START SLAVE;
SHOW SLAVE STATUS\G
2. 在線關閉GTID
自行判斷命令在主庫還是從庫執行
stop slave;
show slave status\G
## 取show slave status\G中的Master_Log_File和Exec_Master_Log_Pos填入
CHANGE MASTER TO
MASTER_AUTO_POSITION = 0,
MASTER_LOG_FILE='mysql-bin.000017',
MASTER_LOG_POS=224126137;
start slave;
show slave status\G
SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;
SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;
SELECT @@GLOBAL.GTID_OWNED;
select * from performance_schema.replication_applier_status_by_worker;
FLUSH LOGS;
SET @@GLOBAL.GTID_MODE = OFF;
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = OFF;
## 修改my.cnf配置文件中GTID相關參數為OFF
gtid-mode = OFF
enforce-gtid-consistency = 1
技術總結
其實在線開啟和在線關閉GTID看上去命令較多,但實際基本都是很快的速度就能完成且對業務幾乎沒有影響,其中更重要的反而是在正式開啟之前的一個校驗過程.