常見的熱備份方案
LVM方案
利用Linux的LVM技術(shù)來實現(xiàn)熱備份,將MySQL的數(shù)據(jù)目錄放到LVM邏輯卷上,然后通過LVM快照技術(shù)備份邏輯卷的內(nèi)容。第一次備份是全量備份,之后的備份都是增量備份。在還原時,將快照中的數(shù)據(jù)目錄恢復到y(tǒng)SQL的數(shù)據(jù)目錄即可。
使用LVM這種技術(shù)不僅可以備份MySQL還可以備份MongoDB等其他數(shù)據(jù)庫,但使用LVM做熱備份方案也比較麻煩,因為需要手動創(chuàng)建邏輯卷、遷移數(shù)據(jù)目錄、創(chuàng)建快照以及給數(shù)據(jù)庫加鎖等等,所以LVM并不是常用的熱備份方案。
XtraBackup方案
因為LVM的麻煩,所以人們都希望使用專業(yè)的工具去做熱備份,這個工具就是XtraBackup。XtraBackup是由Percona開源的免費數(shù)據(jù)庫熱備份工具,它能對InnoDB數(shù)據(jù)庫和XtraDB存儲引擎的數(shù)據(jù)庫非阻塞地備份。因為XtraBackup在備份過程中不會打斷正在執(zhí)行的事務,而事務日志中記錄了哪些是備份前寫入的數(shù)據(jù)哪些是備份后寫入的數(shù)據(jù),所以無需加鎖。
另外,XtraBackup提供了對備份數(shù)據(jù)的壓縮功能,可以節(jié)約備份文件占用的磁盤空間及網(wǎng)絡(luò)帶寬。但XtraBackup在備份使用MyISAM作為存儲引擎的表時會加讀鎖,即表中的數(shù)據(jù)可讀但不可寫,不過這也不是問題,之前提到了可以使用聯(lián)機熱備份的方式來解決加讀鎖的問題。同樣,XtraBackup支持全量備份和增量備份,因為XtraBackup的方便性,所以一般都是采用XtraBackup來做熱備份方案。
XtraBackup熱備份原理
因為XtraBackup是主流的MySQL熱備份方案,所以這里簡單介紹一下XtraBackup熱備份原理:
-
XtraBackup是一種物理備份工具,通過協(xié)議連接到MySQL服務端,然后讀取并復制底層的數(shù)據(jù)文件,完成物理備份。需要注意的是XtraBackup支持對InnoDB做全量備份和增量備份,但只能對MyISAM做全量備份
image.png
現(xiàn)在已經(jīng)知道了XtraBackup是通過讀取并復制底層的數(shù)據(jù)文件,完成物理備份的。其中全量備份比較簡單,直接備份數(shù)據(jù)文件中的所有內(nèi)容即可。而增量備份則需要區(qū)分新數(shù)據(jù)和舊數(shù)據(jù),然后僅備份新數(shù)據(jù),所以稍微復雜以些。
XtraBackup增量備份的原理如下:
增量備份只備份新增的數(shù)據(jù),所以XtraBackup會去讀取數(shù)據(jù)文件中的內(nèi)容來判斷哪些是舊數(shù)據(jù)哪些是新數(shù)據(jù),然后只去備份新數(shù)據(jù)。在MySQL的數(shù)據(jù)文件里,數(shù)據(jù)是存放在
row這種結(jié)構(gòu)中的,而row存放在page中,page則存在于extend中。MySQL會為每一個
page都標記上一個LSN編號,通過對比該編號就可以得知哪些數(shù)據(jù)是新的,哪些數(shù)據(jù)是舊的。然后XtraBackup只需要從數(shù)據(jù)文件中,將這些新的page數(shù)據(jù)備份出來就行了。示意圖:
image.png
那么XtraBackup是如何得知哪些LSN是新的呢?首先我們要知道LSN是一個全局遞增的編號,每次對page中的數(shù)據(jù)進行修改時都會產(chǎn)生新的LSN編號。假設(shè)現(xiàn)在有6個page,各自的LSN編號如下:

上圖中,LSN編號為3的表示被修改過3次,LSN編號為5的表示被修改過5次,以此類推。假設(shè)此時對這些page進行一次全量備份,那么這6個page都會被備份下來。經(jīng)過一段時間后,其中有三個page被修改了,LSN編號發(fā)生了變化,如下所示:

當進行增量備份時,XtraBackup就會將之前備份的page的LSN編號與數(shù)據(jù)文件中與之對應的page的LSN編號進行對比,若數(shù)據(jù)文件里的LSN編號大于備份里的LSN編號則代表數(shù)據(jù)文件中的page是新數(shù)據(jù),那么XtraBackup就會對其進行備份。若等于則代表數(shù)據(jù)沒有發(fā)生變化,不進行備份。因為LSN編號是全局遞增的,所以不存在小于的情況。這就是XtraBackup增量備份的原理。
安裝XtraBackup
在了解了XtraBackup和其熱備份的實現(xiàn)原理后,接下來我們實踐一下如何使用該工具。首先需要安裝官方提供的yum倉庫:
[root@PXC-Node3 ~]# yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
然后激活該yum倉庫:
[root@PXC-Node3 ~]# percona-release setup ps80
現(xiàn)在就可以直接通過yum命令本地安裝XtraBackup了:
[root@PXC-Node3 ~]# yum install -y percona-xtrabackup-24
安裝完成后,輸出一下版本信息驗證xtrabackup命令是否可用:
[root@PXC-Node3 ~]# xtrabackup --version
xtrabackup: recognized server arguments: --server-id=3 --datadir=/var/lib/mysql --log_bin
xtrabackup version 2.4.18 based on MySQL server 5.7.26 Linux (x86_64) (revision id: 29b4ca5)
[root@PXC-Node3 ~]#
常用命令
XtraBackup命令種類:
| 序號 | 命令 | 描述 |
|---|---|---|
| 1 | xbcrypt |
用于加密或解密備份的數(shù)據(jù) |
| 2 | xbstream |
用于壓縮或者解壓縮xbstream文件 |
| 3 | xtrabackup |
用于備份使用InnoDB、XtraDB作為存儲引擎的數(shù)據(jù)表,該命令僅備份表數(shù)據(jù)文件,所以通常用在增量備份上 |
| 4 | innobackupex |
是上面三種命令的perl腳本封裝,可以使用該命令備份MyISAM數(shù)據(jù)表,并且只有使用該命令才能備份表數(shù)據(jù)文件、表定義文件、表索引文件,所以通常用在全量備份上 |
全量熱備份
使用innobackupex命令備份InnoDB數(shù)據(jù)表的流程圖:

使用innobackupex命令進行全量熱備份示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --host=192.168.190.134 --user=admin --password=Abc_123456 --port=3306 /home/backup
-
--defaults-file:指定MySQL的配置文件所在路徑,因為XtraBackup需要通過讀取配置文件才能知道數(shù)據(jù)目錄在哪 -
--host:指定MySQL服務的ip地址,因為全量備份時需要備份表結(jié)構(gòu),所以得連接到MySQL加讀鎖 -
--user:指定使用哪個MySQL用戶進行備份 -
--password:MySQL用戶的密碼 -
--port:指定MySQL服務的端口號 -
/home/backup:備份文件存儲的目錄
備份的文件目錄如下:
[root@PXC-Node3 ~]# ls /home/backup/
2020-01-26_10-33-29
[root@PXC-Node3 ~]# ls /home/backup/2020-01-26_10-33-29/
backup-my.cnf ibdata1 performance_schema test xtrabackup_binlog_info xtrabackup_info
ib_buffer_pool mysql sys tpcc xtrabackup_checkpoints xtrabackup_logfile
[root@PXC-Node3 ~]#
以上這是一個最簡單的全量熱備份示例,可以看到備份出來的目錄和文件有很多,并且也沒有對這些備份文件進行壓縮。如果需要備份的數(shù)據(jù)量比較大的話,不壓縮備份文件就會很占用存儲空間。但使用常規(guī)的壓縮命令,如tar、zip等,則需要兩次I/O操作,因為得先使用XtraBackup備份了數(shù)據(jù)之后,才能對產(chǎn)生的備份文件進行壓縮。因此備份的數(shù)據(jù)量較大時,對系統(tǒng)I/O和CPU的影響就比較明顯。
好在XtraBackup提供了流式壓縮的功能,通過流式壓縮可以將備份數(shù)據(jù)直接寫到壓縮文件中,而不用先備份再壓縮,所以只需要一次I/O操作。如下:

想在備份時使用流式壓縮只需要指定--stream參數(shù)即可,如下示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --host=192.168.190.134 --user=admin --password=Abc_123456 --port=3306 --no-timestamp --stream=xbstream -> /home/backup/backup.xbstream
-
--no-timestamp:指定不生成時間戳目錄 -
--stream:指定使用的壓縮類型,目前只支持tar和xbstream -
/home/backup/backup.xbstream:指定生成的壓縮文件名稱
當備份一些涉及隱私的數(shù)據(jù)時,我們希望對備份文件進行加密,以防備份文件意外泄露時所帶來的影響。而XtraBackup也提供了加密備份的功能,與加密相關(guān)的參數(shù)如下:
| 序號 | 參數(shù) | 描述 |
|---|---|---|
| 1 | --encrypt |
指定用于加密的算法:AES123、AES192、AES256 |
| 2 | --encrypt-threads |
指定執(zhí)行加密的線程數(shù) |
| 3 | --encrypt-chunk-size |
指定加密線程的緩存大小,默認64kb,大小不超過1M |
| 4 | --encrypt-key |
指定用于加解密的密鑰字符串,長度至少24個字符 |
| 5 | --encrypt-key-file |
指定密鑰文件的路徑 |
加密備份示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --host=192.168.190.134 --user=admin --password=Abc_123456 --port=3306 --no-timestamp --stream=xbstream --encrypt=AES256 --encrypt-threads=10 --encrypt-chunk-size 512 --encrypt-key='1K!cNoq&RUfQsY&&LAczTjco' -> /home/backup/encrypt-backup.xbstream
其他常用參數(shù):
| 序號 | 參數(shù) | 描述 |
|---|---|---|
| 1 | --compress |
針對InnoDB數(shù)據(jù)文件進行壓縮,可以與--stream參數(shù)同時使用 |
| 2 | --compress-threads |
指定執(zhí)行壓縮的線程數(shù) |
| 3 | --compress-chunk-size |
指定壓縮線程的緩存大小,默認64kb,大小不超過1M |
| 4 | --include |
指定需要備份的數(shù)據(jù)表的正則表達式 |
| 5 | --galera-info |
指定備份PXC節(jié)點狀態(tài)文件 |
使用示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --host=192.168.190.134 --user=admin --password=Abc_123456 --port=3306 --no-timestamp --stream=xbstream --encrypt=AES256 --encrypt-threads=10 --encrypt-chunk-size 512 --encrypt-key='1K!cNoq&RUfQsY&&LAczTjco' --compress --compress-threads=10 --include=test.student,test.t_orders --galera-info -> /home/backup/backup2.xbstream
-
--include:指明了僅備份test庫下的student和t_orders表,也可以寫正則表達式
全量冷還原
上面介紹了全量熱備份后,我們來看下如何將XtraBackup備份的文件進行還原。在還原這塊只能冷還原,所謂冷還原就是得把數(shù)據(jù)庫停機后進行還原。之所以不存在熱還原,是因為對一個正在運行中的數(shù)據(jù)庫進行在線還原操作,而同時用戶又在讀寫數(shù)據(jù),這就有可能導致數(shù)據(jù)互相覆蓋,使得數(shù)據(jù)庫的數(shù)據(jù)發(fā)生錯亂。
因此,還原這塊就只能是冷還原,本小節(jié)將逐步演示如何使用XtraBackup還原備份文件。首先關(guān)閉MySQL服務:
[root@PXC-Node3 ~]# systemctl stop mysqld
清空數(shù)據(jù)目錄及表分區(qū)的數(shù)據(jù)目錄:
[root@PXC-Node3 ~]# rm -rf /var/lib/mysql/*
[root@PXC-Node3 ~]# rm -rf /mnt/p0/data/*
[root@PXC-Node3 ~]# rm -rf /mnt/p1/data/*
-
Tips:這里由于是示例就直接使用
rm刪除了,如果是實際的運行環(huán)境,建議先使用mv重命名需要刪除的目錄,最后還原完備份文件并驗證沒有問題后,再使用rm刪除,以避免刪庫跑路的悲劇發(fā)生
因為是熱備份,所以事務日志中可能會存在一些未完成的事務,這就需要回滾沒有提交的事務,以及同步已經(jīng)提交的事務到數(shù)據(jù)文件。這里以2020-01-26_10-33-29這個全量備份目錄作為示例,執(zhí)行如下命令:
[root@PXC-Node3 ~]# innobackupex --apply-log /home/backup/2020-01-26_10-33-29/
然后使用以下命令進行備份文件的還原:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --copy-back /home/backup/2020-01-26_10-33-29/
接著給還原后的目錄文件賦予mysql用戶權(quán)限:
[root@PXC-Node3 ~]# chown -R mysql:mysql /var/lib/mysql/*
[root@PXC-Node3 ~]# chown -R mysql:mysql /mnt/p0/data/*
[root@PXC-Node3 ~]# chown -R mysql:mysql /mnt/p1/data/*
到此為止就完成了冷還原,最后啟動MySQL服務并自行驗證下數(shù)據(jù)是否正常即可:
[root@PXC-Node3 ~]# systemctl start mysqld
以上是對沒有使用流式壓縮,也沒有使用加密的備份文件做的演示。如果是備份文件使用了流式壓縮,則需要先使用xbstream命令對其進行解壓。如下示例:
# 創(chuàng)建解壓后文件的存儲目錄
[root@PXC-Node3 ~]# mkdir /home/backup/temp
[root@PXC-Node3 ~]# xbstream -x < /home/backup/backup2.xbstream -C /home/backup/temp/
如果備份文件使用了加密,則在解壓之后還需要對其進行解密:
[root@PXC-Node3 ~]# innobackupex --decompress --decrypt=AES256 --encrypt-key='1K!cNoq\&RUfQsY\&\&LAczTjco' /home/backup/temp
-
Tips:因為
&是特殊字符,所以需要使用\轉(zhuǎn)義一下。其中--decompress是與--compress對應的,用于解壓被壓縮的InnoDB數(shù)據(jù)文件,與解密無關(guān)
增量熱備份
增量熱備份必須以全量熱備份為基礎(chǔ)進行備份,所以在了解了XtraBackup的全量熱備份和全量冷還原后,接下來就可以實踐XtraBackup的增量熱備份了。
注意事項:
- 無論全量熱備份使用了流式壓縮還是內(nèi)容加密,都必須解壓或解密成普通的備份目錄
- 增量熱備份也同樣可以使用流式壓縮和內(nèi)容加密
這里以2020-01-26_10-33-29這個全量備份目錄作為示例,增量熱備份命令如下:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --host=192.168.190.134 --user=admin --password=Abc_123456 --port=3306 --incremental-basedir=/home/backup/2020-01-26_10-33-29/ --incremental /home/backup/increment
-
--incremental-basedir:指定全量備份文件所存儲的目錄,即基于哪個全量備份進行增量備份 -
--incremental:指定采用增量備份 -
/home/backup/increment:增量備份文件所存放的目錄
增量備份的文件目錄如下:
[root@PXC-Node3 ~]# ls /home/backup/increment/
2020-01-26_17-02-21
[root@PXC-Node3 ~]# ls /home/backup/increment/2020-01-26_17-02-21/
backup-my.cnf ibdata1.delta mysql sys tpcc xtrabackup_checkpoints xtrabackup_logfile
ib_buffer_pool ibdata1.meta performance_schema test xtrabackup_binlog_info xtrabackup_info
[root@PXC-Node3 ~]#
可以使用du命令對比一下全量熱備份與增量熱備份的目錄大?。?/p>
[root@PXC-Node3 ~]# du -sh /home/backup/increment/2020-01-26_17-02-21/
3.3M /home/backup/increment/2020-01-26_17-02-21/ # 增量熱備份的目錄大小
[root@PXC-Node3 ~]# du -sh /home/backup/2020-01-26_10-33-29/
836M /home/backup/2020-01-26_10-33-29/ # 全量熱備份的目錄大小
[root@PXC-Node3 ~]#
之后的第二次增量備份就可以不基于全量備份,而是基于第一次的增量備份,這樣每次的增量備份都是一個備份點就像快照一樣。如下示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --user=admin --password=Abc_123456 --incremental-basedir=/home/backup/increment/2020-01-26_17-02-21/ --incremental /home/backup/increment
如果增量備份時需要使用流式壓縮和內(nèi)容加密,則添加相關(guān)參數(shù)即可。如下示例:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --user=admin --password=Abc_123456 --incremental-basedir=/home/backup/increment/2020-01-26_17-02-21/ --incremental --stream=xbstream --encrypt=AES256 --encrypt-threads=10 --encrypt-chunk-size 512 --encrypt-key='1K!cNoq&RUfQsY&&LAczTjco' ./ > /home/backup/increment
-
Tips:這里的
./表示將增量備份所有的內(nèi)容都寫到流式壓縮文件里,壓縮文件則存放在/home/backup/increment目錄下
增量冷還原
經(jīng)過以上小節(jié)可以得知增量熱備份僅備份新數(shù)據(jù),并且生成的備份目錄體積也要比全量熱備份生成的目錄體積要小很多。那么XtraBackup要如何將增量備份的數(shù)據(jù)還原到數(shù)據(jù)庫呢?其實也很簡單,就是先將增量熱備份的數(shù)據(jù)與全量熱備份的數(shù)據(jù)合并,然后基于合并后的備份數(shù)據(jù)去還原即可。
增量熱備份可以有很多個備份點,因為除第一次增量熱備份外,其余的增量熱備份都是基于上一次增量熱備份進行的。所以在還原的時候也可以選擇任意一個備份點去還原,但事務日志的處理步驟與全量冷還原不一樣。
在之前演示全量冷還原的時候,有一個處理事務日志的步驟,同樣增量冷還原也有這個步驟,但是有些差異。上面提到增量熱備份是可以有多個備份點的,那么在還原某一個備份點時就需要處理該備份點及其之前備份點的事務日志,否則就會出現(xiàn)數(shù)據(jù)混亂的情況。如下圖,有三個備份點:

例如,當還原“增量備份1”時,需要先處理其前一個備份點的事務日志,即圖中的“全量熱備份”。接著再處理“增量備份1”這個備份點的事務日志,然后合并“增量備份1”的數(shù)據(jù)到“全量熱備份”中。這樣才能保證多個備份點合并到全量備份點后的數(shù)據(jù)是一致的,最后還原“全量熱備份”中的數(shù)據(jù)即可。
再例如,要還原的是“增量備份2”,那么就得先處理“全量熱備份”,然后處理“增量備份1”,接著處理“增量備份2”,按從前往后的順序依次將這三個備份點的事務日志都給處理了后,才能合并備份點的數(shù)據(jù)到全量備份中,最后還原“全量熱備份”中的數(shù)據(jù)。其余則以此類推......
接下來實操一下增量冷還原,這里有三個與上圖對應的備份點目錄:
/home/backup/2020-01-26_10-33-29/ # 全量熱備份
/home/backup/increment/2020-01-27_10-11-24/ # 增量備份1
/home/backup/increment/2020-01-27_10-15-11/ # 增量備份2
因為是冷還原,所以得先關(guān)閉MySQL服務:
[root@PXC-Node3 ~]# systemctl stop mysqld
在本例中要還原的是“增量備份2”這個備份點的數(shù)據(jù),按照之前的說明,首先處理全量備份點的事務日志,執(zhí)行如下命令:
[root@PXC-Node3 ~]# innobackupex --apply-log --redo-only /home/backup/2020-01-26_10-33-29/
-
--redo-only:指定不回滾未提交的事務,因為下個備份點的事務日志里可能會提交該備份點未提交的事務。如果回滾了就會導致下個備份點無法正常提交
然后處理“增量備份1”的事務日志,并將"增量備份1"的數(shù)據(jù)合并到全量備份點上:
[root@PXC-Node3 ~]# innobackupex --apply-log --redo-only /home/backup/2020-01-26_10-33-29/ --incremental-dir=/home/backup/increment/2020-01-27_10-11-24/
-
--incremental-dir:指定要合并到全量備份的增量備份目錄
接著處理“增量備份2”的事務日志,并將"增量備份2"的數(shù)據(jù)合并到全量備份點上。由于只還原到“增量備份2”這個備份點,所以就不需要加上--redo-only參數(shù)了,因為沒有下個備份點了:
[root@PXC-Node3 ~]# innobackupex --apply-log /home/backup/2020-01-26_10-33-29/ --incremental-dir=/home/backup/increment/2020-01-27_10-15-11/
與全量冷還原一樣,也需清空數(shù)據(jù)目錄及表分區(qū)的數(shù)據(jù)目錄:
[root@PXC-Node3 ~]# rm -rf /var/lib/mysql/*
[root@PXC-Node3 ~]# rm -rf /mnt/p0/data/*
[root@PXC-Node3 ~]# rm -rf /mnt/p1/data/*
完成以上步驟后,就可以使用如下命令完成備份文件的還原了:
[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --copy-back /home/backup/2020-01-26_10-33-29/ # 注意這里指定的是全量備份點的目錄
接著給還原后的目錄文件賦予mysql用戶權(quán)限:
[root@PXC-Node3 ~]# chown -R mysql:mysql /var/lib/mysql/*
[root@PXC-Node3 ~]# chown -R mysql:mysql /mnt/p0/data/*
[root@PXC-Node3 ~]# chown -R mysql:mysql /mnt/p1/data/*
到此為止還原就完成了,最后啟動MySQL服務并自行驗證下數(shù)據(jù)是否正常即可:
[root@PXC-Node3 ~]# systemctl start mysqld

