技術分享 | MySQL 線上開啟 GTID 的每個階段是要做什麼

愛可生雲資料庫 發表於 2022-01-27
MySQL

作者:餘振興

愛可生 DBA 團隊成員,熱衷技術分享、編寫技術文件。

本文來源:原創投稿

*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。


基本概述

我們知道 MySQL 有 2 種方式指定複製同步的方式,分別為:

  1. 基於 binlog 檔名及位點的指定方式

    • 匿名事務(Anonymous_gtid_log_event)
  2. 基於GTID(全域性事務 ID )的指定方式

    • GTID事務(Gtid_log_event)

而基於 GTID 的方式在一主多從的架構下主從切換有著明顯優勢外,對於日常複製異常的故障診斷也更為方便,在日常運維或 MySQL 升級過程中我們免不了要做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 時,只會在錯誤日誌提示,不會直接報錯,

技術分享 | MySQL 線上開啟 GTID 的每個階段是要做什麼

<br/>

## 該操作在主從庫均執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;
2. 設定 GTID 校驗 ENFORCE_GTID_CONSISTENCY 為 ON

確認上一個步驟未在錯誤日誌中出現相關 Warning 資訊後,正式開啟 GTID 一致性校驗,當設定為 ON 後,如果再執行 CREATE TABLE AS SELECT 語句則會直接報錯

技術分享 | MySQL 線上開啟 GTID 的每個階段是要做什麼

<br/>

## 該操作在主從庫均執行
SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;
3. 設定 GTID_MODE為OFF_PERMISSIVE

如前面對 GTID_MODE 可取值的描述,該操作表示新產生的事務依舊是匿名事務,但也允許有 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

技術分享 | MySQL 線上開啟 GTID 的每個階段是要做什麼

確保回放執行緒回放的事務都已是GTID事務

技術分享 | MySQL 線上開啟 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 的逆向操作,以下只寫出步驟和具體命令,不做詳細解釋

  1. 先將 GTID 模式的複製改為基於 POS 點的複製
  2. 設定 GTID_MODE為ON_PERMISSIVE
  3. 設定 GTID_MODE為OFF_PERMISSIVE
  4. 觀測 GTID_OWNED 狀態變數變為空值及 replication_applier_status_by_worker 表中事務均轉為匿名事務
  5. 觸發 FLUSH LOGS
  6. 設定 GTID_MODE 為 OFF
  7. 設定 ENFORCE_GTID_CONSISTENCY 為 OFF
  8. 修改 my.cnf 配置檔案中 GTID 相關引數為 OFF
1. 將複製改為基於POS點方式
stop slave;
show slave status\G

## 取show slave status\G中的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 看上去命令較多,但實際基本都是很快的速度就能完成且對業務幾乎沒有影響,其中更重要的反而是在正式開啟之前的一個校驗過程。

參考連結

https://dev.mysql.com/doc/ref...

https://dev.mysql.com/doc/ref...