問題定位 | XtraBackup 8.0 資料重建避坑事件始末

RadonDB開源社群發表於2021-06-15

作者:盧文雙 資深資料庫研發工程師 目前負責青雲雲資料庫的研發工作,熱衷於研究主流資料庫架構、原始碼,對關係型資料庫 MySQL/PostgreSQL 及分散式資料庫有深入研究。

前言

在為 Xenon[1] 適配新版 Percona XtraBackup 8.0[2](原有程式碼適配於 2.4 版本)時遇到的一些問題,在定位過程中對比了 XtraBackup 2.4 和 8.0 的異同。

版本資訊[3]:

  • Percona-Server 8.0.19-10
  • Percona-Xtrabackup 8.0.13

問題描述

問題 1

MySQL 8.0 + Semi-Sync + 持續寫入資料期間執行重建後, change master to && start slave 報錯:

Last_Error: Could not execute Write_rows event on table db1.t1; Duplicate entry '28646' for key 't1.PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000052, end_log_pos 437

問題 2

MySQL 8.0 + Group Replication + 持續寫入資料期間執行重建後,change master to && start group_replication 報錯:

2020-08-21T14:51:09.977606+08:00 61 [System] [MY-010597] [Repl] 'CHANGE MASTER TO FOR CHANNEL 'group_replication_applier' executed'. Previous state master_host='<NULL>', master_port= 0, master_log_file='', master_log_pos= 4, master_bind=''. New state master_host='<NULL>', master_port= 0, master_log_file='', master_log_pos= 4, master_bind=''.
2020-08-21T14:51:09.987494+08:00 61 [ERROR] [MY-013124] [Repl] Slave SQL for channel 'group_replication_applier': Slave failed to initialize relay log info structure from the repository, Error_code: MY-013124
2020-08-21T14:51:09.987542+08:00 61 [ERROR] [MY-011534] [Repl] Plugin group_replication reported: 'Error while starting the group replication applier thread'
2020-08-21T14:51:09.987651+08:00 7 [ERROR] [MY-011669] [Repl] Plugin group_replication reported: 'Unable to initialize the Group Replication applier module.'
2020-08-21T14:51:09.987831+08:00 7 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: '[GCS] The member is leaving a group without being on one.'

要解釋這兩個問題,首先要弄清楚 XtraBackup 2.4 和 8.0 的區別。

XtraBackup 2.4/8.0 版本區別

通過查到可知 XtraBackup 2.4 與 8.0 版本備份記錄資訊有如下不同點:

  • 2.4 備份生成的 xtrabackup_binlog_info 檔案記錄的 GTID 資訊是準確的,但是備份恢復後 show master status 顯示的 GTID 是不準確的;
  • 8.0 備份的例項中只有 InnoDB 表時,xtrabackup_binlog_info 檔案記錄的 GTID 資訊不一定是準確的,但是備份恢復後 show master status 顯示的 GTID 是準確的;
  • 8.0 備份的例項中有非 InnoDB 表時,xtrabackup_binlog_info 檔案記錄的 GTID 資訊是準確的,備份恢復後 show master status 顯示的 GTID 也是準確的。

兩個版本執行過程如下:

2.4 8.0
1. start backup
2. copy ibdata1 / copy .ibd file
3. excuted FTWRL
4. backup non-InnoDB tables and files
5. writing xtrabackup_binlog_info
6. executed FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
7. executed UNLOCK TABLES
8. copying ib_buffer_pool
9. completed OK!




1. start backup
2. copy .ibd file
3. backup non-InnoDB tables and files
4. executed FLUSH NO_WRITE_TO_BINLOG BINARY LOGS
5. selecting LSN and binary log position from p_s.log_status
6. copy last binlog file
7. writing /mysql/backup/backup/binlog.index
8. writing xtrabackup_binlog_info
9. executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
10. copy ib_buffer_pool
11. completed OK!

注意:當存在非 InnoDB 表時,8.0 會執行 FTWRL。

通過兩個版本執行過程命令不難看出,主要區別在於 8.0 版本當只存在 InnoDB 表時,執行步驟 5 命令來獲取 LSN、binlog position、GTID。

手冊中[4],對於表 log_status 的描述如下:

The log_status table provides information that enables an online backup tool to copy the required log files without locking those resources for the duration of the copy process.

When the log_status table is queried, the server blocks logging and related administrative changes for just long enough to populate the table, then releases the resources. The log_status table informs the online backup which point it should copy up to in the source's binary log and gtid_executed record, and the relay log for each replication channel. It also provides relevant information for individual storage engines, such as the last log sequence number (LSN) and the LSN of the last checkpoint taken for the InnoDB storage engine.

從上述手冊描述可知,performance_schema.log_status 是 MySQL 8.0 提供給線上備份工具獲取複製資訊的表格,查詢該表時,mysql server 將阻止日誌的記錄和相關的更改來獲取足夠的時間以填充該表,然後釋放資源。

log_status 表通知線上備份工具當前主庫的 binlog 的位點和 gtid_executed 的值以及每個複製通道的 relay log。另外,它還提供了各個儲存引擎的相關資訊,比如,提供了 InnoDB 引擎使用的最後一個日誌序列號(LSN)和最後一個檢查點的 LSN。

表 log_status 定義引數資訊示例如下:

-- Semi-Sync
mysql> select * from performance_schema.log_status\G
*************************** 1. row ***************************
    SERVER_UUID: 6b437e80-e5d5-11ea-88e3-52549922fdbb
          LOCAL: {"gtid_executed": "6b437e80-e5d5-11ea-88e3-52549922fdbb:1-201094", "binary_log_file": "mysql-bin.000079", "binary_log_position": 195}
    REPLICATION: {"channels": []}
STORAGE_ENGINES: {"InnoDB": {"LSN": 23711425885, "LSN_checkpoint": 23711425885}}
1 row in set (0.00 sec)

-- Group Replication
mysql> select * from performance_schema.log_status\G
*************************** 1. row ***************************
    SERVER_UUID: 7bd32480-e5d5-11ea-8f8a-525499cfbb7d
          LOCAL: {"gtid_executed": "aaaaaaaa-aaaa-aaaa-aaaa-53ab6ea1210a:1-11", "binary_log_file": "mysql-bin.000003", "binary_log_position": 1274}
    REPLICATION: {"channels": [{"channel_name": "group_replication_applier", "relay_log_file": "mysql-relay-bin-group_replication_applier.000004", "relay_log_position": 311, "relay_master_log_file": "", "exec_master_log_position": 0}, {"channel_name": "group_replication_recovery", "relay_log_file": "mysql-relay-bin-group_replication_recovery.000003", "relay_log_position": 151, "relay_master_log_file": "", "exec_master_log_position": 0}]}
STORAGE_ENGINES: {"InnoDB": {"LSN": 20257208, "LSN_checkpoint": 20257208}}
1 row in set (0.00 sec)

問題定位

問題 1:MySQL 8.0 + Semi-Sync 重建

Xenon 原有的重建邏輯適配於 MySQL 5.6/5.7(重建過程中 Xenon 程式存活),一直無問題。

Xenon 重建邏輯

  1. 禁用 raft,將 Xenon 狀態設為 LEARNER;
  2. 如 mysql 程式存在,則 stop mysql
  3. 清空 MySQL 資料目錄;
  4. 執行 xtrabackup --backup 以 xbstream 方式獲取對端資料;
  5. 執行 xtrabackup --prepare 應用 redo log;
  6. 啟動 mysql;
  7. 執行 stop slave; reset slave all
  8. 執行 reset master,以 xtrabackup_binlog_info 檔案中的 GTID 為準設定 gtid_purged;
  9. 啟用 raft,將 Xenon 狀態設為 FOLLOWER 或 IDLE;
  10. 等待 Xenon 自動 change master to 到主節點;
  11. 執行 start slave

Duplicate entry '28646' for key 't1.PRIMARY' 表示主鍵衝突,說明表中已存在相同主鍵的行。跟蹤重建過程中的 general log,發現在第 6 和第 7 步中間,也就是設定 gtid_purged 之前憑空多出了 change master tostart slave 操作。

grneral log(部分)

通過下面示例程式碼資訊可看出,在設定 gtid_purged 之前已經啟用複製獲取了一部分資料,那麼 xtrabackup_binlog_info 中的內容就不再準確,之後設定的 GTID 與實際資料就不一致,實際的資料比設定的 GTID 要多,會引起主鍵衝突。

SET GLOBAL rpl_semi_sync_master_enabled=OFF
SET GLOBAL read_only = 1
SET GLOBAL super_read_only = 1
START SLAVE
STOP SLAVE
CHANGE MASTER TO MASTER_HOST = '192.168.0.3', MASTER_USER = 'qc_repl', MASTER_PASSWORD = <secret>, MASTER_PORT = 3306, MASTER_AUTO_POSITION = 1
START SLAVE
BEGIN
COMMIT /* implicit, from Xid_log_event */
......
BEGIN
COMMIT /* implicit, from Xid_log_event */
SET GLOBAL rpl_semi_sync_master_enabled=OFF
SET GLOBAL read_only = 1
SET GLOBAL super_read_only = 1
START SLAVE
BEGIN
COMMIT /* implicit, from Xid_log_event */
......
BEGIN
COMMIT /* implicit, from Xid_log_event */
STOP SLAVE
RESET SLAVE ALL
RESET MASTER
SET GLOBAL gtid_purged='6b437e80-e5d5-11ea-88e3-52549922fdbb:1-102610
'
START SLAVE
SET GLOBAL read_only = 1
SET GLOBAL super_read_only = 1
SET GLOBAL sync_binlog=1000
SET GLOBAL innodb_flush_log_at_trx_commit=1
SHOW SLAVE STATUS
SHOW MASTER STATUS
SET GLOBAL rpl_semi_sync_master_enabled=OFF
SET GLOBAL read_only = 1
SET GLOBAL super_read_only = 1
START SLAVE
SHOW SLAVE STATUS
SHOW MASTER STATUS
STOP SLAVE
CHANGE MASTER TO MASTER_HOST = '192.168.0.3', MASTER_USER = 'qc_repl', MASTER_PASSWORD = <secret>, MASTER_PORT = 3306, MASTER_AUTO_POSITION = 1
START SLAVE 
疑問 1

問:為什麼之前 MySQL 5.6/5.7 從沒遇到過這個問題呢?

答:多次測試發現在 MySQL 5.6/5.7 中 set gtid_purged 前執行 change master to & start slave 會報復制錯誤 Slave failed to initialize relay log info structure from the repository ,在 reset slave all; reset master、set gtid_purged 後再執行 change master to & start slave 就可以正常複製,資料無誤。

疑問 2

問:Xenon 中哪塊邏輯引起的額外的 change master tostart slave

答:在重建期間 Xenon 會設為 LEARNER 角色,而該角色在探測到 MySQL Alive後,會 change master 到主節點。

解決方案:
  • 去掉 LEARNER 對 MySQL 的監聽,要等 raft 狀態變為 FOLLOWER 後,由 FOLLOWER 的監聽執行緒 change master to 到主節點。[5]

  • 對於 MySQL 8.0,重建後無需執行 reset master & set gtid_purged 操作。[6]

問題 2:MySQL 8.0 + Group-Replication 重建後無法啟動 MGR

根據報錯資訊 Slave failed to initialize relay log info structure from the repository 看,應該是 XtraBackup 重建後的資料目錄保留了 slave 複製資訊導致的。

解決方案:

在啟動組複製前執行 reset slavereset slave all 即可解決。

XtraBackup 8.0 避坑總結

  • 使用 Xtrabackup 8.0 重建叢集節點後,無需執行 reset master & set gtid_purged 操作;
  • 使用 Xtrabackup 8.0 重建 Group-Replication 叢集節點後,啟動組複製前要先執行 reset slavereset slave all 清除 slave 資訊,否則 start group_replication 會失敗。

備註參考

[1]. Xenon : https://github.com/radondb/xenon

[2]. Percona XtraBackup : https://www.percona.com/software/mysql-database/percona-xtrabackup

[3]. 版本名含義參考:https://www.percona.com/blog/2020/08/18/aligning-percona-xtrabackup-versions-with-percona-server-for-mysql/

[4]. MySQL 官方手冊:https://dev.mysql.com/doc/refman/8.0/en/performance-schema-log-status-table.html

[5]. pr104:https://github.com/radondb/xenon/pull/104

[6]. pr102:https://github.com/radondb/xenon/pull/102

關於 RadonDB

RadonDB 開源社群是一個面向雲原生、容器化的資料庫開源社群, 為資料庫技術愛好者提供圍繞主流開源資料庫(MySQL、PostgreSQL、Redis、MongoDB、ClickHouse 等)的技術分享平臺,並提供企業級 RadonDB 開源產品及服務。

目前 RadonDB 開源資料庫系列產品已被 光大銀行、浦發矽谷銀行、哈密銀行、泰康保險、太平保險、安盛保險、陽光保險、百年人壽、安吉物流、安暢物流、藍月亮、天財商龍、羅克佳華、升哲科技、無錫匯跑體育、北京電信、江蘇交通控股、四川航空、昆明航空、國控生物 等上千家企業及社群使用者採用。

RadonDB 可基於雲平臺與 Kubernetes 容器平臺交付,不僅提供覆蓋多場景的資料庫產品解決方案,而且提供專業的叢集管理和自動化運維能力,主要功能特性包括:高可用主從切換、資料強一致性、讀寫分離、一鍵安裝部署、多維指標監控&告警、彈性擴容&縮容、橫向自由擴充套件、自動備份&恢復、同城多活、異地災備 等。RadonDB 僅需企業及社群使用者專注於業務層邏輯開發,無需關注叢集高可用選型、管理和運維等複雜問題,幫助企業及社群使用者大幅度提升業務開發與價值創新的效率!

GitHub:

https://github.com/radondb

微信群: 請搜尋新增群助手微訊號 radondb

相關文章