數據庫備份恢復是 DBA 的 “保命” 技能,生產業務不僅要保證有合適的備份策略,也要定期驗證備份的有效性和恢復演練流程,因為數據恢復和驗證可能會涉及多方合作,演練可以讓災難真正發生時,多方配合有條不紊的將數據恢復,從而盡可能的減少 RTO 讓業務快速恢復。
Xtrabackup 是 MySQL 社區唯一一款開源物理熱備工具,本篇文章將詳細介紹 DBA 如何使用它,以及備份恢復的詳細步驟。
官方文檔地址:https://www.percona.com/software/documentation
?Xtrabackup 介紹
Xtrabackup 是由 Percona 公司開源的一款 MySQL 物理熱備份工具,目前社區非常活躍,是 MySQL 開源社區的主流備份工具,深受用戶喜愛。
?物理備份與邏輯備份區別
物理備份是指,通過拷貝物理文件進行備份,物理備份的優點:
-
?備份和恢復速度快,配置完成后直接基于備份啟動數據庫即可。
-
無需實例在線,實例在關閉的情況下,也可以拷貝物理文件。
物理備份的缺點:
-
備份文件大。
-
恢復時,對平臺、操作系統、MySQL 版本和參數,必須一致或兼容。
-
?只能在本地發起備份。
-
因為是直接拷貝數據文件,表空間中的 “空間碎片” 無法通過備份恢復收縮。
MySQL 常用的邏輯備份工具是 mysqldump,邏輯備份的優點:
-
可移植性強。恢復時,對平臺、操作系統、MySQL 版本無要求。
-
使用靈活,可備份恢復單庫單表,結構等。
-
備份文件較小。
-
可遠程發起備份。
-
恢復后,能有效收縮空間。
邏輯備份的缺點:
-
備份、恢復速度慢。尤其是恢復速度,相當于批量執行 SQL 備份過大時恢復會很慢。
-
備份可能會 “污染” 緩沖池。
?Xtrabackup 系列版本
目前 Xtrabackup 活躍的大版本有三個:
-
?Xtrabackup 2.4 適用于 MySQL 5.6 和 MySQL 5.7。
-
?Xtrabackup 8.0 適用于 MySQL 8.0。
-
?Xtrabackup 8.1 適用于 MySQL 8.1。
注意,三個版本不能混用,因為 MySQL 8.0 版本 redo log 和數據字典格式都發生了變化,可能會出現不兼容的情況。
Xtrabackup 部署
下載安裝包
從下方鏈接中,可以獲得 Percona 所有產品的安裝包:
https://www.percona.com/downloads
這里可以選擇 Xtrabackup 對應的系列版本。版本號規則,例如 Percona XtraBackup 8.0.30-23 的版本號定義了以下信息:
-
基礎版本 - 最左邊的數字表示用作基礎的 MySQL 8.0 版本。
-
次要版本 - 表示軟件版本的內部編號。
需要注意的是 Percona XtraBackup 編號在 8.0.14 版本之后發生了變化,以使 Percona XtraBackup 版本與 MySQL 保持一致。
所以在備份前,請確保 Percona XtraBackup 的版本等于或高于正在備份的數據庫版本。
二進制部署
下載二進制的 Xtrabackup 壓縮包,開箱即用:
# 解壓縮
tar?-zxvf percona-xtrabackup-8.0.34-29-Linux-x86_64.glibc2.17.tar.gz
?????
# 移動目錄
mv?percona-xtrabackup-8.0.34-29-Linux-x86_64.glibc2.17?/usr/local/xtrabackup-8.0.34
# 配置軟鏈接
ln?-sf /usr/local/xtrabackup-8.0.34/bin/* /usr/bin/
完成以上三步,輸入 xtrabackup --version 就可以看到版本信息。
xtrabackup version 8.0.34-29 based on MySQL server 8.0.34 Linux (x86_64) (revision id: 5ba706ee)
程序文件介紹
接下來看看 bin 目錄下,各文件的具體作用:
-
xbcloud:與流式備份相結合,可將備份存儲到 OSS 對象存儲上。
-
xbcloud_osenv:對 xbcloud 的二次封裝,
-
xbcrypt:用來加密解密。
-
xbstream:用來解壓流式備份集。
-
xtrabackup:備份的主程序,備份和恢復的工具。
在 xtrabackup 2.4 版本中,還有 innobackupex 文件,不過它只是 xtrabackup 的一個軟鏈。
在 xtrabackup 2.3 版本之前,xtrabackup 只支持 innodb 表的備份,MyISAM 等非事務引擎的表的備份是通過 innobackupex 來實現的。它是使用 Perl 腳本編寫的,而 xtrabackup 是使用 C++ 程序編譯的二進制文件。
xtrabackup 來備份事務引擎的表,innobackupex 備份非事務引擎的表,兩個程序協作完成最終的備份一致性。但既然是兩個不同的工具協同處理一個任務,就必然涉及到兩個工具之間,信息的交互。當時信息交互的方案,是通過創建和刪除臨時文件彼此交互。但這種方式存在風險,例如在備份過程中,臨時文件被誤刪等。
于是從 xtrabackup 2.3 開始,Percona 用 C 語言重寫了 innobackupex,并將其作為 xtrabackup 的一個軟鏈。它依然支持之前的語法,但不會增加新特性,所有的新特性只會集成在 xtrabackup 中。
xtrabackup 8.0 中,innobackupex 被移除了,所以建議從 xtrabackup 2.3 開始,只使用 xtrabackup 二進制程序進行備份恢復操作。
本篇文章的所有演示也只會使用 xtrabackup。
備份需要的權限
Xtrabackup 備份工具,備份時用戶需要有以下權限:
-
Reload:用于執行 FLUSH TABLES WITH REDO LOCK 和 FLUSH NO_WRITE_TO_BINLOG TABLES 是必需權限。
-
Replication client:用于執行 SHOW MASTER STATUS 和 SHOW SLAVE STATUS 查看位點信息,是必需權限。
-
?BACKUP_ADMIN:用于執行 LOCK INSTANCE FOR BACKUP,是必需權限。
-
?Process:用于執行 SHOW ENGINE INNODB STATUS 和 SHOW PROCESSLIST 是必需權限。
-
SYSTEM_VARIABLES_ADMIN:用于在增量備份時執行 SET GLOBAL mysqlbackup.backupid = xxx 操作,是非必需權限。
-
SUPER:在指定 --kill-long-queries-timeout 需要殺掉慢查詢,和從庫備份指定 --safe-slave-backup 需要重啟復制,需要用到該權限。
-
SHOW VIEW:確認是否有非 INNODB 引擎表。
-
如果使用 Page Tracking 進行增量備份,還需要 mysql.component 表的查詢權限。
-
如果指定 --history 還需要 performance_schema.xtraback_history 的 SELECT、INSERT、CREATE、ALTER 權限。
以下是 MySQL 8.0 以上版本的完整授權示例:
CREATE?USER?'bkpuser'@'localhost'?IDENTIFIED?BY?'s3cr%T';
GRANT?BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT?ON?*.*?TO?'bkpuser'@'localhost';
GRANT?SELECT?ON?performance_schema.log_status?TO?'bkpuser'@'localhost';
GRANT?SELECT?ON?performance_schema.keyring_component_status?TO?bkpuser@'localhost';
GRANT?SELECT?ON?performance_schema.replication_group_members?TO?bkpuser@'localhost';
以下是 MySQL 5.7 版本的完整授權示例:
???????
CREATE?USER?'bkpuser'@'localhost'?IDENTIFIED?BY?'s3cret';
GRANT?RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT?ON?*.*?TO?'bkpuser'@'localhost';
Xtrabackup 使用場景
Xtrabackup 備份恢復有三個階段,第一階段是備份階段,將物理文件拷貝到備份目錄。第二階段是 Prepare 階段,應用 redo log 將數據文件恢復到備份結束時的一致性狀態。第三階段是恢復階段,就是將備份文件拷貝到 MySQL 數據目錄下面,除了使用 Xtrabackup 命令拷貝,我們也可以手動拷貝。
本地全量備份
xtrabackup --backup --slave-info ?-u root -H 127.0.0.1 -P3306 -p'YouPassword'?--parallel=5 --target-dir=/data/backup/bakup_`date?+"%F_%H_%M_%S"` 2>/tmp/xtrabackup.log
關鍵參數介紹:
-
?--backup:發起全量備份。
-
-u, -H, -P, -p:連接 mysql 實例,用戶名、主機 IP、端口、密碼。
-
--slave-info:記錄 slave 復制位點信息,一般備份從庫需要指定該參數。
-
--target-dir:備份文件的存放路徑。
-
--parallel:并發拷貝的線程數。
-
2>/tmp/xtrabackup.log:將備份過程中的日志重定向到 /tmp/xtrabackup.log 文件中。
Tips:Xtrabackup 備份成功后,日志最后一行會輸出 completed OK!
備份出來的文件中,除了數據文件,還有以下額外的文件:
-
backup-my.cnf:該文件不是 MySQL 參數文件的備份,只是記錄了一些 Innodb 引擎的參數,會在 Prepare 階段用到。
-
xtrabackup_logfile:該文件用來保存拷貝的 redo log。
-
xtrabackup_binlog_info:binlog 位點信息和 GTID 信息。使用該備份恢復后,需要從該 binlog 位點進行增量恢復。
-
xtrabackup_slave_info:如果是對從庫進行備份,指定 --slave-info 該文件會記錄主節點的位點信息,取自 SHOW SLAVE STATUS 中的 Relay_Master_Log_File 和 Exec_Master_Log_Pos。如果是給主庫備份,該文件為空。
-
xtrabackup_checkpoints:該文件記錄了備份類型和 LSN 信息。
-
xtrabackup_info:該文件中,記錄備份的詳細信息。
-
xtrabackup_tablespaces:記錄備份集中表空間的信息。
本地壓縮備份
壓縮備份通過 --compress 指定壓縮算法,具體命令如下:
xtrabackup?--backup --slave-info?-u root -H?127.0.0.1?-P3306 -p'YouPassword'?--compress --parallel=5?--target-dir=/data/backup/bakup_`date +"%F_%H_%M_%S"`
Xtrabackup 8.0 支持兩種壓縮算法 zstd(默認) 和 lz4 算法,Xtrabackup 5.7 僅支持 quicklz 算法。
其中 zstd 在解壓縮時依賴 zstd 需要安裝才能進行解壓。quicklz 算法依賴 qpress 也需要安裝后才能進行解壓。
在 Prepare 階段之前,必須要先進行解壓,命令如下:
xtrabackup?--decompress --parallel=5?--target-dir=/data/backup/bakup_2023-11-13_14_44_55/
在解壓過程中,需要注意:
-
解壓過程中,同樣可以指定?
--parallel
?參數,進行并行解壓。 -
解壓后,默認不會刪除壓縮文件。如果需要刪除,可以指定?
--remove-original
?參數。 -
即便壓縮文件沒有被刪除,當使用?
--copy-back
?將備份拷貝到數據目錄時,默認也不會拷貝這些壓縮文件。
使用 compress 壓縮只支持幾種限定的算法,如果想要使用其他算法,就需要結合流式備份。
全量流式備份
流式備份指將備份數據通過流的方式輸出到 STDOUT,而不是備份文件中。結合管道,可將多個功能組合在一起,如壓縮、加密、流控等。
在 xtrabackup 2.4 版中支持 tar 和 xbstream 流格式,但 tar 格式不支持并行備份。
在 xtrabackup 8.0 中,僅支持 xbstream 流格式,不再支持 tar 格式。
備份到遠程主機
使用下方命令通過管道組合,實現本地不落盤,將備份保存到遠程主機。???????
xtrabackup?--backup --slave-info? -u root -H?127.0.0.1?-P3306 -p'YouPassword'?\
?--stream=xbstream --target-dir=/data/backup/bakup_`date +"%F_%H_%M_%S"`?2>/data/backup/xtrabackup.log ?\
?| ssh root@172.16.104.7?"cat - ?> /data/backup/backup.xbstream"
遠程恢復的時候,需要先使用 xbstream 命令進行解壓:
xbstream?-x --parallel=10?-C /data/backup/20231113?< ./backup.xbstream
xbstream 中的 -x 表示解壓,--parallel 表示并行度,-C 指定解壓的目錄,最后一級目錄必須存在。
gzip 本地壓縮備份
使用流式備份,配合管道使用 gzip 命令對備份在本地進行壓縮。???????
xtrabackup --backup --slave-info ?-u root -H 127.0.0.1 -P3306 -p'YouPassword'?\
?--stream=xbstream --target-dir=/data/backup/bakup_`date?+"%F_%H_%M_%S"` \
?| gzip - > /data/backup/backup1.gz
恢復時需要先使用 gunzip 解壓,再使用 xbstream 解壓,才能進行 Prepare 階段。
gzip 遠程壓縮備份
使用流式備份,配合管道將備份 ssh 到遠程進行壓縮。???????
xtrabackup?--backup --slave-info? -u root -H?127.0.0.1?-P3306 -p'YouPassword'?\
?--stream=xbstream --target-dir=/data/backup/bakup_`date +"%F_%H_%M_%S"` \
?| ssh root@172.16.104.7?"gzip - > /data/backup/backup1.gz"
Tips:恢復解壓時的步驟與本地壓縮備份相同。
遠程備份限速
直接備份到遠程服務器,如果擔心備份會占用較大的網絡帶寬,可以使用 pv 命令限速。
下面是 pv 工具的安裝方法:???????
wget?https://www.ivarch.com/programs/sources/pv-1.8.0.tar.gz
tar?xzf pv-1.8.0.tar.gz
cd?pv-1.8.0
sh?./configure
make
sudo?make install
下方命令表示限速 10MB 將備份發送到遠程服務器壓縮保存。???????
xtrabackup?--backup --slave-info? -u root -H?127.0.0.1?-P3306 -p'YouPassowrd'?\
?--stream=xbstream --target-dir=/data/backup/bakup_`date +"%F_%H_%M_%S"` \
| pv -q -L10m | ssh root@172.16.104.7?"cat - ?> /data/backup/backup.xbstream"
pv 命令中,-q 是指 quiet 不輸出進度信息,-L 是指傳輸速率 10m 指 10MB。
Tips:恢復解壓時的步驟與備份到遠程主機相同。
全量備份恢復數據
前面 3 個小節,介紹的都是全量備份階段,本小節將介紹如何恢復全量備份。
首先要進行 Prepare 階段,在該階段 Xtrabackup 會啟動一個嵌入的 InnoDB 實例來進行 Crash Recovery。該實例的緩沖池的大小由?--use-memory
?參數指定,默認為 100MB。如果有充足的內存,通過設置較大的 memory 可以減少 Prepare 階段花費的時間。???????
# 進入到備份目錄執行該命令
xtrabackup?--prepare --use-memory=2G --target-dir=./
Prepare 階段執行完成后,備份目錄下才會生成 redo log 文件,可據此判斷備份文件是否執行過 Prepare 階段。
Prepare 階段完成后,下面進入恢復階段,可以手動拷貝文件到數據目錄,也可以使用 xtrabackup 工具進行拷貝。???????
# 進入到備份目錄執行該命令
xtrabackup?--defaults-file=/etc/my.cnf --copy-back --parallel=10?--target-dir=./
命令中?--copy-back
?表示將備份數據文件拷貝到 MySQL 數據目錄下。如果在存儲空間不足的情況下,可以使用?--move-back
?表示移動備份文件。
另外,恢復實例的數據目錄必須為空,所以在恢復前,我們需要清空 MySQL 數據目錄,或者將其 mv 備份后,重新創建同名目錄。數據文件拷貝到目標目錄后,需要修改文件屬組。
chown?-R mysql:mysql /data/mysql_80/
至此,備份就恢復完成了,直接啟動 MySQL 即可。
chown?-R mysql:mysql /data/mysql_80/
增量備份與恢復
xtrabackup 支持增量備份。在做增量備份之前,需要先做一個全量備份。xtrabackup 會基于 innodb page 的 lsn 號來判斷是否需要備份一個 page。如果 page lsn 大于上次備份的 lsn 號,就需要備份該 page。
增量備份
先進行一次全量備份。???????
# 先創建全量備份的目錄
mkdir?/data/backup/full
??????
xtrabackup --backup --slave-info ?-u root -H?127.0.0.1?-P3306?\
? -p'YouPassword'?--stream=xbstream --target-dir /data/backup/full \
?--extra-lsndir=/data/backup/full \
?2>/data/backup/full/backup_full.log | gzip - ?> /data/backup/full/backup_full.gz
備份命令加上 了--extra-lsndir 選項,將 xtrabackup_checkpoints 單獨輸出到文件。增量備份時需要根據 xtrabackup_checkpoints中的 lsn。以下是相關文件。???????
# ls?-l?/data/backup/full
-rw-r--r-- 1 root root 3014835 6月 ?25 16:35 backup_full.gz
-rw-r--r-- 1 root root ? 40313 6月 ?25 16:35 backup_full.log
-rw-r--r-- 1 root root ? ? 134 6月 ?25 16:35 xtrabackup_checkpoints
-rw-r--r-- 1 root root ? ? 673 6月 ?25 16:35 xtrabackup_info
現在,發起增量備份。???????
# 先創建增量備份的目錄
mkdir?/data/backup/inc1
???????
xtrabackup --backup --slave-info ?-u root -H 127.0.0.1 -P3306 \
? -p'YouPassword'?--stream=xbstream --target-dir /data/backup/inc1 \
?--extra-lsndir=/data/backup/inc1 \
?--incremental-basedir=/data/backup/full \
?2>/data/backup/inc1/backup_inc1.log?| gzip - ?> /data/backup/inc1/backup_inc1.gz
--incremental-basedir:全量備份或上一次增量備份 xtrabackup_checkpoints 文件所在目錄。
增量備份也可以在上一次增量備份的基礎上進行:
???????
# 先創建增量備份的目錄
mkdir?/data/backup/inc2
???????
xtrabackup --backup --slave-info ?-u root -H 127.0.0.1 -P3306 \
? -p'YouPassword'?--stream=xbstream --target-dir /data/backup/inc2 \
?--extra-lsndir=/data/backup/inc2 \
?--incremental-basedir=/data/backup/inc1 \
?2>/data/backup/inc2/backup_inc2.log?| gzip - ?> /data/backup/inc2/backup_inc2.gz
增量備份恢復
恢復增量備份時,需要先對基礎全量備份進行恢復,然后再依次按增量備份的時間進行恢復。
?
這個例子中,相關備份文件的目錄結構如下:???????
/data/backup
├── full
│ ? ├── backup_full
│ ? ├── backup_full.log
│ ? ├── xtrabackup_checkpoints
│ ? └── xtrabackup_info
├── inc1
│ ? ├── backup_inc1.gz
│ ? ├── backup_inc1.log
│ ? ├── xtrabackup_checkpoints
│ ? └── xtrabackup_info
├── inc2
│ ? ├── backup_inc2.gz
│ ? ├── backup_inc2.log
│ ? ├── xtrabackup_checkpoints
│ ? └── xtrabackup_info
首先,恢復全量備份。???????
cd?/data/backup/full
gunzip backup_full.gz
# 需要先刪除這兩個文件,否則 xbstream 提取文件時有沖突
rm?xtrabackup_checkpoints xtrabackup_info
xbstream -x -v < backup_full
xtrabackup --prepare --apply-log-only --target-dir=. > prepare_full.log 2>&1
恢復全量備份時,需要加上 apply-log-only 參數。如果不加上 apply-log-only 參數,執行 prepare 的最后階段,會回滾未提交的事務,但是這些事務可能在下一次增量備份時已經提交了。
查看日志,確認這一步驟執行成功(最后一行日志顯示“completed OK!”):
[Note] [MY-011825] [Xtrabackup] completed OK!
接下來,恢復第一個增量備份。?????
cd?/data/backup/inc1
gunzip backup_inc1.gz
# 需要先刪除這兩個文件,否則 xbstream 提取文件時有沖突
rm?xtrabackup_checkpoints xtrabackup_info
# 提取文件
xbstream -x -v < backup_inc1
# 恢復增量備份時,切換到全量備份的目錄執行
cd?/data/backup/full
xtrabackup --prepare --apply-log-only --incremental-dir=/data/backup/inc1 --target-dir=.
恢復增量備份時,加上 apply-log-only 參數,參數 --incremental-dir 設置為增量備份文件所做目錄。日主輸出 completed OK! 表示任務運行成功。
接下來,恢復第二個增量備份,也就是最后一個增量備份。???????
cd?/data/backup/inc2
gunzip backup_inc2.gz
# 需要先刪除這兩個文件,否則xbstream提取文件時有沖突
rm?xtrabackup_checkpoints xtrabackup_info
# 提取文件
xbstream -x -v < backup_inc2
# 恢復增量備份時,切換到全量備份的目錄執行
cd?/data/backup/full
xtrabackup --prepare --incremental-dir=/data/backup/inc2 --target-dir=.
恢復最后一個增量備份時,不需要再加上 --apply-log-only。這一步執行完成后,xtrabackup_checkpoints文件內容如下:????????
# cat xtrabackup_checkpoints
backup_type?= full-prepared
from_lsn?=?0
to_lsn?=?42439917
last_lsn?=?52717010
flushed_lsn?=?52617342
redo_memory?=?0
redo_frames?=?0
backup_type 為 full-prepared,表示 Prepare 階段已經完成。后面操作和恢復全量備份基本一樣。復制文件啟動數據庫即可。