Xtrabackup備份Xtrabackup



Xtrabackup 是由 percona 開源的免費數據庫熱備份軟件,它能對 InnoDB 和 XtraDB 存儲引擎的數據庫非阻塞地備份。

為了方便建立從庫,Xtrabackup 在備份完成後會將 binlog position 與 GTID 的相關信息保存於 xtrabackup_binlog_info 文件中。

但是當你使用 Xtrabackup 生成的備份建立一個從庫時,會發現恢復後的實例執行 show master status,顯示的 Executed_Gtid_Set 與 xtrabackup_binlog_info 文件中記錄的信息並不一致,而且使用 Xtrabackup 2.4 與 8.0(對 MySQL 8.0 進行備份)生成的備份在恢復後,信息不一致的表現又不相同。本篇文章主要針對該現象進行簡單的分析。


一、Xtrabackup 2.4.18 for MySQL 5.7.26

現象

1. 使用 Xtrabackup 工具備份後,xtrabackup_binlog_info 文件記錄的信息如下:

<code>\\# cat xtrabackup_binlog_infomysql-bin.000003    86412752    55d3d9b9-4d49-11ea-932c-02000aba3fa6:1-595859/<code>

2. 將該備份恢復至一個新實例並啟動該實例,執行 show master status; 查看信息:

<code>mysql> show master status\\G*************************** 1. row ***************************             File: mysql-bin.000001         Position: 154     Binlog_Do_DB:Binlog_Ignore_DB:Executed_Gtid_Set: 55d3d9b9-4d49-11ea-932c-02000aba3fa6:1-3266611 row in set (0.00 sec)/<code>

此時會發現使用備份恢復的實例顯示已執行過的 GTID 是 1-326661,而備份文件顯示的是 1-595859,這是否表示兩者相差的 GTID:326662-595859 代表的事務丟失了?

通過對原實例(進行備份的實例)的 binlog 進行解析,來查詢 GTID:326662-595859 這部分事務所生成的數據在新實例(通過備份恢復的實例)上是否存在。可以發現 GTID:326662-595859 這部分事務的數據都存在於新實例上,也就是說數據與 xtrabackup_binlog_info 文件記錄的是一致的,只不過與 show master status 命令獲取的信息的不一致。

原因分析

首先我們要清楚 Xtrabackup 2.4 的備份流程,大致如下:

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!

結合備份時的 general log 可知,Xtrabackup 在執行 ftwrl 並備份完所有非 InnoDB 表格的文件後通過show master status 獲取了 binlog position 和 GTID 的信息,將其記錄到 xtrabackup_binlog_info 文件中。

那麼 show master status 獲取的是哪些信息?

該命令提供本實例的 binlog 文件的狀態信息,顯示正在寫入的 binlog 文件,以及當前的binlog position,並且 MySQL 5.7 在 MySQL 庫下引入了 gtid_executed 表,該表會記錄當前執行過的 GTID。

那麼目前看來問題可能就出在 gtid_executed 表格上,通過測試和官方文檔提供的信息可知,該表格雖然是 InnoDB 表,但是其中的數據並非是實時更新的,且該表格記錄信息的方式存在以下兩個情況:

1. 如果禁用了 log_bin,實例不會在該表格記錄任何信息;若從庫的 log_slave_updates 為 OFF,那麼從庫會在應用 relay-log 中的每個事務時執行一次 insert mysql.gtid_executed 的操作。

2. 如果啟用了 log_bin,則該表格記錄的是在 binlog 發生切換(rotate)的時候直到上一個 binlog 文件執行過的全部 GTID,而此時 show master status 獲取的 Gtid 信息不再由 mysql.gtid_executed 表提供,而是由全局系統變量 gtid_exected 提供;如果服務器意外停止,則當前 binlog 文件中的 Gtid 集合不會保存在 mysql.gtid_executed 表中,在實例恢復期間,這些 Gtid 從 binlog 文件中讀取並添加到表中。

小結

所以當備份恢復時,實際 show master status 可能會出現以下情況:

1. 當 log_bin 禁用或者 log_slave_updates 為 OFF 時,備份恢復後的實例 show master status 顯示為空。

2. 當開啟了 log_bin,但是該實例並未發生過 binlog 的切換時,備份恢復後的實例 show master status 顯示也為空。

3. 當開啟了 log_bin,其該實例的 binlog 發生過切換時,備份恢復後的實例 show master status 顯示的信息會比 xtrabackup_binlog_info 文件中記錄的 GTID 缺失一部分,這一部分就是 mysql.gtid_executed 表格未記錄的部分。


二、Xtrabackup 8.0.8 for MySQL 8.0.18

現象

1. 使用 Xtrabackup 工具備份後,xtrabackup_binlog_info 文件記錄的信息如下:

<code># # cat xtrabackup_binlog_infobinlog.000033    1459    70ec927f-4c6d-11ea-b88c-02000aba3fb1:1-621683/<code>

2. 查看備份實例相對應的 binlog 解析後的內容:

<code># mysqlbinlog -vv binlog.000033 | less定位至 70ec927f-4c6d-11ea-b88c-02000aba3fb1:621683# at 508#200213 13:46:47 server id 663728  end_log_pos 583      GTID    last_committed=0        sequence_number=2       rbr_only=yes    original_committed_timestamp=1581572807720907   immediate_commit_timestamp=1581572807720907     transaction_length=317/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;# original_commit_timestamp=1581572807720907 (2020-02-13 13:46:47.720907 CST)# immediate_commit_timestamp=1581572807720907 (2020-02-13 13:46:47.720907 CST)/*!80001 SET @@session.original_commit_timestamp=1581572807720907*//*!*/;/*!80014 SET @@session.original_server_version=80018*//*!*/;/*!80014 SET @@session.immediate_server_version=80018*//*!*/;SET @@SESSION.GTID_NEXT= '70ec927f-4c6d-11ea-b88c-02000aba3fb1:621683'/*!*/;# at 583#200213 13:46:47 server id 663728  end_log_pos 659      Query   thread_id=214   exec_time=0     error_code=0SET TIMESTAMP=1581572807/*!*/;BEGIN/*!*/;# at 659#200213 13:46:47 server id 663728  end_log_pos 708      Rows_query# insert into t1 values(null,2)# at 708#200213 13:46:47 server id 663728  end_log_pos 758      Table_map: `mysqlslap`.`t1` mapped to number 314# at 758#200213 13:46:47 server id 663728  end_log_pos 798      Write_rows: table id 314 flags: STMT_END_FBINLOG 'x+JEXh2wIAoAMQAAAMQCAACAAB1pbnNlcnQgaW50byB0MSB2YWx1ZXMobnVsbCwyKQ==x+JEXhOwIAoAMgAAAPYCAAAAADoBAAAAAAEACW15c3Fsc2xhcAACdDEAAgMDAAIBAQA=x+JEXh6wIAoAKAAAAB4DAAAAADoBAAAAAAEAAgAC/wCKAAEAAgAAAA=='/*!*/;### INSERT INTO `mysqlslap`.`t1`### SET###   @1=65674 /* INT meta=0 nullable=0 is_null=0 */###   @2=2 /* INT meta=0 nullable=1 is_null=0 */# at 798#200213 13:46:47 server id 663728  end_log_pos 825      Xid = 2436045COMMIT/*!*/;/<code>

可以發現該文件提供的 binlog position 與 GTID 並不對應。而 binlog.000033:1459 對應的 GTID 是 70ec927f-4c6d-11ea-b88c-02000aba3fb1:621685 提交後的下一個位置:

<code># at 1142#200213 13:46:47 server id 663728  end_log_pos 1217     GTID    last_committed=2        sequence_number=4       rbr_only=yes    original_committed_timestamp=1581572807724646   immediate_commit_timestamp=1581572807724646     transaction_length=317/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;# original_commit_timestamp=1581572807724646 (2020-02-13 13:46:47.724646 CST)# immediate_commit_timestamp=1581572807724646 (2020-02-13 13:46:47.724646 CST)/*!80001 SET @@session.original_commit_timestamp=1581572807724646*//*!*/;/*!80014 SET @@session.original_server_version=80018*//*!*/;/*!80014 SET @@session.immediate_server_version=80018*//*!*/;SET @@SESSION.GTID_NEXT= '70ec927f-4c6d-11ea-b88c-02000aba3fb1:621685'/*!*/;# at 1217#200213 13:46:47 server id 663728  end_log_pos 1293     Query   thread_id=215   exec_time=0     error_code=0SET TIMESTAMP=1581572807/*!*/;BEGIN/*!*/;# at 1293#200213 13:46:47 server id 663728  end_log_pos 1342     Rows_query# insert into t1 values(null,2)# at 1342#200213 13:46:47 server id 663728  end_log_pos 1392     Table_map: `mysqlslap`.`t1` mapped to number 314# at 1392#200213 13:46:47 server id 663728  end_log_pos 1432     Write_rows: table id 314 flags: STMT_END_FBINLOG 'x+JEXh2wIAoAMQAAAD4FAACAAB1pbnNlcnQgaW50byB0MSB2YWx1ZXMobnVsbCwyKQ==x+JEXhOwIAoAMgAAAHAFAAAAADoBAAAAAAEACW15c3Fsc2xhcAACdDEAAgMDAAIBAQA=x+JEXh6wIAoAKAAAAJgFAAAAADoBAAAAAAEAAgAC/wCMAAEAAgAAAA=='/*!*/;### INSERT INTO `mysqlslap`.`t1`### SET###   @1=65676 /* INT meta=0 nullable=0 is_null=0 */###   @2=2 /* INT meta=0 nullable=1 is_null=0 */# at 1432#200213 13:46:47 server id 663728  end_log_pos 1459     Xid = 2436047COMMIT/*!*/;# at 1459/<code>

3. 再看將備份恢復到一個新實例並啟動後,執行 show master status 顯示的信息:

<code>mysql> show master status\\G*************************** 1. row ***************************             File: binlog.000034         Position: 191     Binlog_Do_DB:Binlog_Ignore_DB:Executed_Gtid_Set: 70ec927f-4c6d-11ea-b88c-02000aba3fb1:1-6216851 row in set (0.00 sec)/<code>

可以發現與 Xtrabackup 2.4 不同的是,該備份的 xtrabackup_binlog_info 文件記錄的信息並不準確,而備份恢復後顯示的信息卻是準確的。

原因

首先我們來看一下 Xtrabackup 8.0 針對 MySQL 8.0 備份的大致過程:

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!

由以上步驟可知,Xtrabackup 8.0 對 MySQL 8.0 的備份與 Xtrabackup 2.4 略有不同,根據 percona 官方文檔的信息,當 MySQL 8.0 中僅存在 InnoDB 引擎的表格時,不再執行ftwrl(當存在非 InnoDB 的表格或者使用 --slave-info 選項時會執行),而是根據上述步驟的第 5 步,Xtrabackup 8.0 會通過

<code>SELECT server_uuid, local, replication, storage_engines FROM performance_schema.log_status/<code>

來獲取 LSN 、binlog position and Gtid。

1. performance_schema.log_status 是 MySQL 8.0 提供給在線備份工具獲取複製日誌文件信息的表格。查詢 log_status 表時,服務器將阻止日誌的記錄和相關的更改來獲取足夠的時間以填充該表,然後釋放資源。Log_status 表通知在線備份工具應記錄主庫的 binlog 的哪個位點和 gtid_executed 的值,還有每個複製通道的 relay log。它還為各個存儲引擎提供了相關信息,例如 InnoDB 存儲引擎使用的最後一個日誌序列號(LSN)和最後一個檢查點的 LSN。

2. 經過測試發現,當無數據寫入時, performance_schema.log_status 提供的 binlog position 與 GTID 是一致的,但是當有大量數據持續寫入時,該表格提供的 binlog position 與 GTID 信息將不再一致,如下圖:


Xtrabackup備份Xtrabackup_binlog_info文件記錄GTID信息是否準確

3. 既然 performance_schema.log_status 提供的信息不一致,那麼為什麼備份恢復後,GTID 沒有缺失?這是因為 Xtrabackup 8.0 在備份過程中多了兩步操作,FLUSH NO_WRITE_TO_BINLOG BINARY LOGS 和 copy binlog,Xtrabackup 8.0 在備份完非 InnoDB 表格的文件時會先切換 binlog,然後將切換後的 binlog 也進行備份,這樣使用該備份恢復的新實例在啟動後不僅會讀取 gtid_executed 表,也會讀取 binlog 文件來更新 GTID,就可以保持與備份時 xtrabackup_binlog_info 文件記錄的 binlog position 保持一致(需要注意的是 MySQL 8.0 的 gtid_executed 表格不再是當 binlog 切換時更新,而是會不斷的實時更新,但需要注意在有大量數據寫入時也不能做到和全局變量 gtid_exeuted 保持嚴格一致)。

4. 當 MySQL 8.0 中存在非 InnoDB 的表格,比如 MyISAM 表時,Xtrabackup 8.0 會在執行完 FLUSH NO_WRITE_TO_BINLOG BINARY LOGS 後執行 ftwrl,此時查詢 performance_schema.log_status 得到的 binlog position 與 GTID 是一致的,且備份恢復後 show master status 顯示的信息也與 xtrabackup_binlog_info 文件記錄的信息一致。


總結

1. Xtrabackup 2.4 備份後生成的 xtrabackup_binlog_info 文件記錄的 GTID 信息是準確的,但是備份恢復後 show master status 顯示的 GTID 是不準確的。

2. Xtrabackup 8.0 在備份只有 InnoDB 表的實例時,xtrabackup_binlog_info 文件記錄的 GTID 信息不一定是準確的,但是備份恢復後 show master status 顯示的 GTID 是準確的。

3. Xtrabackup 8.0 在備份有非 InnoDB 表格的實例時,xtrabackup_binlog_info 文件記錄的 GTID 信息是準確的,備份恢復後 show master status 顯示的 GTID 也是準確的。

注意:此處的“準確”主要指 xtrabackup_binlog_info 文件中記錄的 GTID 與備份中實際的 binlog position & 數據是否一致。


分享到:


相關文章: