溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

關(guān)于數(shù)據(jù)庫(kù)的各種備份與還原姿勢(shì)詳解

發(fā)布時(shí)間:2020-02-14 11:09:20 來源:網(wǎng)絡(luò) 閱讀:549 作者:ZeroOne01 欄目:MySQL數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)的冷備份與熱備份

數(shù)據(jù)導(dǎo)出不完全等于數(shù)據(jù)備份:

  • 數(shù)據(jù)導(dǎo)出是指將數(shù)據(jù)庫(kù)中的數(shù)據(jù)逆向成SQL語句進(jìn)行導(dǎo)出,所以導(dǎo)出的是SQL文件。通常用作把數(shù)據(jù)從一個(gè)系統(tǒng)遷移到另一個(gè)系統(tǒng),目的是屏蔽系統(tǒng)之間的差異性
  • 數(shù)據(jù)備份是指將數(shù)據(jù)庫(kù)中數(shù)據(jù)存儲(chǔ)的相關(guān)文件進(jìn)行拷貝,用于保存一個(gè)數(shù)據(jù)庫(kù)的全部物理數(shù)據(jù),所以備份后的數(shù)據(jù)與原本數(shù)據(jù)在細(xì)節(jié)及狀態(tài)上都是完全一致的。不會(huì)像SQL那樣在使用了一些函數(shù)的情況下,可能會(huì)在不同的時(shí)間點(diǎn)或不同的系統(tǒng)上產(chǎn)生不一樣的結(jié)果

冷備份與熱備份:

  • 冷備份:在數(shù)據(jù)庫(kù)已經(jīng)關(guān)閉的情況下,對(duì)數(shù)據(jù)的備份稱作冷備份
  • 熱備份:與冷備份相反,在數(shù)據(jù)庫(kù)節(jié)點(diǎn)不停機(jī)的狀態(tài)下進(jìn)行的備份被稱作熱備份

冷備份的限制:

  • 數(shù)據(jù)庫(kù)必須停機(jī)備份,這對(duì)一些線上數(shù)據(jù)庫(kù)是無法接受的
  • 備份的數(shù)據(jù)文件非常占用存儲(chǔ)空間,并且不支持增量備份
  • 冷備份是備份所有的數(shù)據(jù)文件和日志文件,所以無法單獨(dú)備份某個(gè)邏輯庫(kù)和數(shù)據(jù)表

聯(lián)機(jī)冷備份:

單節(jié)點(diǎn)的數(shù)據(jù)庫(kù)在冷備份時(shí)需要停機(jī),這就會(huì)對(duì)業(yè)務(wù)系統(tǒng)產(chǎn)生影響。為了解決這個(gè)問題,我們可以組建集群然后挑選集群中的一個(gè)節(jié)點(diǎn)進(jìn)行停機(jī)冷備份。由于集群中還有其他節(jié)點(diǎn)在運(yùn)行,所以不必?fù)?dān)心影響正在運(yùn)行的系統(tǒng)。等備份結(jié)束之后再啟動(dòng)該節(jié)點(diǎn),這樣就能解決停機(jī)備份帶來的影響

熱備份的限制:

  • 數(shù)據(jù)庫(kù)在熱備份的時(shí)候會(huì)全局加讀鎖,備份期間節(jié)點(diǎn)只能讀取數(shù)據(jù)不能寫入數(shù)據(jù)

聯(lián)機(jī)熱備份:

同樣的方式,為了避免全局加鎖,我們可以挑選集群中的一個(gè)節(jié)點(diǎn)與其他節(jié)點(diǎn)解除數(shù)據(jù)同步關(guān)系后進(jìn)行熱備份。等待備份完成后,再去恢復(fù)與集群中其他節(jié)點(diǎn)的數(shù)據(jù)同步關(guān)系。這樣在備份過程中就只有該節(jié)點(diǎn)會(huì)加讀鎖,其他節(jié)點(diǎn)不會(huì)受到影響

聯(lián)機(jī)熱備份與聯(lián)機(jī)冷備份該如何選擇:

建議選擇聯(lián)機(jī)熱備份,因?yàn)闊醾浞菘梢赃x擇全量備份或增量備份。而冷備份只能選擇全量備份,當(dāng)后期數(shù)據(jù)量很大的時(shí)候,冷備份需要耗費(fèi)很多的時(shí)間,并且由于是全量備份也需要占用更多的存儲(chǔ)空間。熱備份只有在第一次備份的時(shí)候需要選擇全量備份,后續(xù)備份只需要增量備份新數(shù)據(jù)即可。 因此,熱備份在存儲(chǔ)空間的占用及備份耗費(fèi)的時(shí)間上都優(yōu)于冷備份


實(shí)踐聯(lián)機(jī)冷備份

認(rèn)識(shí)MySQL中與數(shù)據(jù)相關(guān)的文件

上一小節(jié)提到了數(shù)據(jù)備份是指將數(shù)據(jù)庫(kù)中數(shù)據(jù)存儲(chǔ)的相關(guān)文件進(jìn)行拷貝,而這些文件有很多,所以讓我們來簡(jiǎn)單認(rèn)識(shí)下MySQL中與數(shù)據(jù)相關(guān)的文件。

首先是組成邏輯庫(kù)的文件,在MySQL中一個(gè)邏輯庫(kù)實(shí)際由多個(gè)文件組成,其結(jié)構(gòu)如下:
關(guān)于數(shù)據(jù)庫(kù)的各種備份與還原姿勢(shì)詳解

  • OPT文件:定義字符集和字符集的排序規(guī)則,該文件是一個(gè)文本文件
  • FRM文件:這是數(shù)據(jù)表的定義文件,包含了數(shù)據(jù)表的結(jié)構(gòu)信息。無論數(shù)據(jù)表使用的什么存儲(chǔ)引擎,每一個(gè)數(shù)據(jù)表的定義文件一定是FRM文件
  • ISL文件:該文件只有創(chuàng)建了表分區(qū)才會(huì)出現(xiàn),它存儲(chǔ)著表分區(qū)數(shù)據(jù)文件所在的路徑
  • MyISAM:
    • MYD文件:MyISAM的數(shù)據(jù)文件
    • MYI文件:MyISAM的索引文件
  • InnoDB:
    • IBD文件:InnoDB的索引及數(shù)據(jù)文件,該文件是一個(gè)二進(jìn)制文件

FRM文件在很多情況下都會(huì)被用到,例如數(shù)據(jù)庫(kù)在執(zhí)行SQL語句之前,先會(huì)審查SQL語句中用到的一些字段是否在FRM文件中定義了?;蛘邤?shù)據(jù)庫(kù)在優(yōu)化SQL語句時(shí),通過FRM文件判斷where子句中的字段是否是主鍵列或索引列等。因?yàn)?code>FRM文件經(jīng)常會(huì)被使用,所以該文件是一個(gè)二進(jìn)制文件

MySQL中的其他文件:

  • auto.cnf文件:該文件存儲(chǔ)MySQL實(shí)例的UUID,即server-uuid,在集群中可以作為節(jié)點(diǎn)的唯一標(biāo)識(shí)
  • grastate.dat文件:該文件保存的是PXC的同步信息
  • gvwstate.dat文件:該文件保存的是PXC集群中其他節(jié)點(diǎn)的信息
  • .pem:該文件存儲(chǔ)的是加解密用的證書和密鑰信息
  • .sock:套接字文件,用于本地連接MySQL
  • .err:錯(cuò)誤日志文件,MySQL所有錯(cuò)誤信息都會(huì)保存在該文件中
  • .pid:MySQL進(jìn)程id文件
  • ib_buffer_pool:InnoDB緩存文件
  • ib_logfile:InnoDB事務(wù)日志(redo)
  • ibdata:InnoDB共享表空間文件
  • logbin:日志文件(binlog)
  • index:日志索引文件
  • ibtmp:臨時(shí)表空間文件

數(shù)據(jù)文件的碎片整理

數(shù)據(jù)文件中的碎片是什么:

  • 我們都知道向數(shù)據(jù)表寫入數(shù)據(jù),數(shù)據(jù)文件的體積會(huì)增大。但是刪除數(shù)據(jù)文件中的數(shù)據(jù)時(shí),數(shù)據(jù)文件體積并不會(huì)減小,而數(shù)據(jù)被刪除后留下的空白就被稱作為碎片

MySQL的數(shù)據(jù)文件一直存在著碎片化問題,MySQL之所以不會(huì)自動(dòng)整理碎片縮減數(shù)據(jù)文件的體積,是因?yàn)檫@個(gè)整理過程是會(huì)鎖表的。如果每刪除一條數(shù)據(jù)就鎖表整理碎片,那么勢(shì)必會(huì)對(duì)數(shù)據(jù)表的讀寫造成很大的影響。不過MySQL在寫入新數(shù)據(jù)時(shí),會(huì)優(yōu)先將其寫入碎片空間,所以數(shù)據(jù)文件中的碎片空間對(duì)日常運(yùn)行沒有什么影響。

但是對(duì)于數(shù)據(jù)庫(kù)備份這個(gè)場(chǎng)景來說,如果數(shù)據(jù)文件中存在著大量的碎片,就會(huì)導(dǎo)致實(shí)際有意義的數(shù)據(jù)沒多少,而數(shù)據(jù)文件的體積又很大。這對(duì)備份來說就很占用存儲(chǔ)空間和傳輸帶寬,所以在進(jìn)行備份之前,需要對(duì)數(shù)據(jù)文件的碎片進(jìn)行一個(gè)整理,盡量縮減數(shù)據(jù)文件的體積。

MySQL中整理數(shù)據(jù)文件碎片的SQL語句如下:

alter table ${table_name} engine=InnoDB;

需要注意的是,在執(zhí)行該SQL之前,記得先將用于備份的數(shù)據(jù)庫(kù)節(jié)點(diǎn)的binlog給關(guān)掉。避免binlog中記錄了該SQL,導(dǎo)致在節(jié)點(diǎn)備份完成恢復(fù)到集群后,其他節(jié)點(diǎn)同步了該SQL出現(xiàn)整個(gè)集群鎖表的情況。所以需要注釋掉MySQL配置文件中的以下兩個(gè)參數(shù),在備份完成后再打開:

# log_bin
# log_slave_updates

冷備份

在前面介紹了一些前置知識(shí)后,本小節(jié)就逐步演示一下如何實(shí)踐聯(lián)機(jī)冷備份。我這里事先準(zhǔn)備了一個(gè)由三個(gè)節(jié)點(diǎn)組成的PXC集群:
關(guān)于數(shù)據(jù)庫(kù)的各種備份與還原姿勢(shì)詳解

首先挑選集群中的任意一個(gè)節(jié)點(diǎn)作為備份節(jié)點(diǎn),然后停止該節(jié)點(diǎn):

[root@PXC-Node3 ~]# systemctl stop mysqld

編輯配置文件,注釋binlog相關(guān)參數(shù):

[root@PXC-Node3 ~]# vim /etc/percona-xtradb-cluster.conf.d/mysqld.cnf
[mysqld]
...

#log-bin
#log_slave_updates

然后注釋PXC集群相關(guān)參數(shù):

[root@PXC-Node3 ~]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[mysqld]
#wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
#wsrep_cluster_address=gcomm://192.168.190.132,192.168.190.133,192.168.190.134
#wsrep_slave_threads=8
#wsrep_log_conflicts
#wsrep_cluster_name=pxc-cluster
#wsrep_node_name=pxc-node-03
#pxc_strict_mode=DISABLED
#wsrep_sst_method=xtrabackup-v2
#wsrep_node_address=192.168.190.134
#wsrep_sst_auth=admin:Abc_123456

修改完畢后,啟動(dòng)MySQL服務(wù),此時(shí)該節(jié)點(diǎn)就退出了PXC集群:

[root@PXC-Node3 ~]# systemctl start mysqld

該節(jié)點(diǎn)的數(shù)據(jù)文件有1.1個(gè)G:

[root@PXC-Node3 ~]# du -h /var/lib/* |grep /var/lib/mysql$
1.1G    /var/lib/mysql
[root@PXC-Node3 ~]# 

本示例中是對(duì)test庫(kù)進(jìn)行備份,所以在進(jìn)行備份之前,需要對(duì)test庫(kù)下所有的表進(jìn)行碎片整理。由于表比較多,我這里編寫了一個(gè)簡(jiǎn)單的Java程序來實(shí)現(xiàn):

import com.mysql.jdbc.Driver;

import java.sql.*;
import java.util.ArrayList;

/**
 * 數(shù)據(jù)表碎片整理
 *
 * @author 01
 * @date 2020-01-25
 **/
public class CleanFragments {

    public static void main(String[] args) throws SQLException {
        DriverManager.registerDriver(new Driver());
        String url = "jdbc:mysql://192.168.190.134:3306/test?useSSL=false";
        String username = "admin";
        String password = "Abc_123456";

        try (Connection connection = DriverManager.getConnection(url, username, password);
             PreparedStatement pst = connection.prepareStatement("show tables;")) {
            ResultSet resultSet = pst.executeQuery();

            ArrayList<String> tableNames = new ArrayList<>();
            while (resultSet.next()) {
                tableNames.add(resultSet.getString(1));
            }

            for (String tableName : tableNames) {
                if ("t_range_1".equals(tableName)) {
                    continue;
                }
                System.out.println("整理 " + tableName + " 表碎片...");
                pst.execute("alter table " + tableName + " engine=InnoDB;");
            }
        }
        System.out.println("整理完畢...");
    }
}

碎片整理完成后,停止MySQL服務(wù),因?yàn)槔鋫浞菪枰C(jī):

[root@PXC-Node3 ~]# systemctl stop mysqld

然后就可以開始備份了,其實(shí)備份的過程也很簡(jiǎn)單,沒用到啥高大上的特殊技術(shù),就是使用tar命令將MySQL數(shù)據(jù)目錄打成一個(gè)壓縮包即可。例如我這里的數(shù)據(jù)目錄是/var/lib/mysql,所以執(zhí)行的命令如下:

# 先進(jìn)入到/var/lib/目錄下
[root@PXC-Node3 ~]# cd /var/lib/
# 然后對(duì)數(shù)據(jù)目錄進(jìn)行打包,mysql.tar.gz是打包后的文件名,存放在/home目錄下
[root@PXC-Node3 /var/lib]# tar -zcvf /home/mysql.tar.gz ./mysql
  • Tips:數(shù)據(jù)目錄是由配置文件中的datadir參數(shù)定義的

如果創(chuàng)建了表分區(qū),并且將表分區(qū)映射到了其他目錄上,那么就還需要對(duì)表分區(qū)進(jìn)行打包。例如我這里有兩個(gè)表分區(qū),分別映射到了/mnt/p0/data//mnt/p1/data/目錄,所以執(zhí)行的命令如下:

[root@PXC-Node3 ~]# cd /mnt/
[root@PXC-Node3 /mnt]# tar -zcvf /home/p0.tar.gz ./p0/data/
[root@PXC-Node3 /mnt]# tar -zcvf /home/p1.tar.gz ./p1/data/

到此備份完成后,恢復(fù)配置文件中所注釋的配置項(xiàng),然后重啟節(jié)點(diǎn)讓該節(jié)點(diǎn)重新加入到PXC集群中即可。由于沒啥需要特殊說明的,所以這里就不演示了。


冷還原

演示了如何冷備份后,接下來則演示如何將備份文件冷還原到其他的PXC節(jié)點(diǎn)上。首先將備份文件傳輸?shù)叫枰€原的節(jié)點(diǎn)上,可以使用scprsync命令在Linux系統(tǒng)之間傳輸文件,如下示例:

[root@PXC-Node3 /home]# scp ./mysql.tar.gz 192.168.190.133:/home/mysql.tar.gz
[root@PXC-Node3 /home]# scp ./p0.tar.gz 192.168.190.133:/home/p0.tar.gz
[root@PXC-Node3 /home]# scp ./p1.tar.gz 192.168.190.133:/home/p1.tar.gz

還原節(jié)點(diǎn)接收到的備份文件如下:

[root@PXC-Node2 ~]# cd /home/
[root@PXC-Node2 /home]# ls
mysql.tar.gz  p0.tar.gz  p1.tar.gz
[root@PXC-Node2 /home]#

除此之外還需要進(jìn)行一些準(zhǔn)備工作,因?yàn)閭浞莨?jié)點(diǎn)是存在表分區(qū)的,并且映射了相應(yīng)的數(shù)據(jù)目錄,若還原節(jié)點(diǎn)不存在則需要?jiǎng)?chuàng)建。如下示例:

[root@PXC-Node2 ~]# mkdir /mnt/p0/
[root@PXC-Node2 ~]# mkdir /mnt/p1/

由于是冷還原,所以和冷備份一樣也需要先停止還原節(jié)點(diǎn):

[root@PXC-Node2 ~]# systemctl stop mysqld

還原MySQL的數(shù)據(jù)目錄,命令如下:

# 先備份原本的數(shù)據(jù)目錄,以防萬一
[root@PXC-Node2 ~]# mv /var/lib/mysql /var/lib/mysql-backup
# 將壓縮文件解壓到/var/lib/目錄下
[root@PXC-Node2 /home]# tar -zxvf mysql.tar.gz -C /var/lib/

然后是還原表分區(qū)數(shù)據(jù)目錄:

[root@PXC-Node2 /home]# tar -zxvf p0.tar.gz -C /mnt/
[root@PXC-Node2 /home]# tar -zxvf p1.tar.gz -C /mnt/

刪除auto.cnf文件,不然uuid重復(fù)的話,該節(jié)點(diǎn)是無法啟動(dòng)的:

[root@PXC-Node2 ~]# rm -rf /var/lib/mysql/auto.cnf

如果你是使用PXC集群中的首節(jié)點(diǎn)作為備份節(jié)點(diǎn),那么就還需要將grastate.dat文件中的safe_to_bootstrap參數(shù)修改為0,普通節(jié)點(diǎn)則不需要。如下示例:

[root@PXC-Node2 ~]# vim /var/lib/mysql/grastate.dat
...

safe_to_bootstrap: 0

到此就算是還原完成了,啟動(dòng)MySQL服務(wù)即可:

[root@PXC-Node2 ~]# systemctl start mysqld

剩下就是自行驗(yàn)證下該節(jié)點(diǎn)的數(shù)據(jù)是否正確還原了,能否與集群中其他節(jié)點(diǎn)進(jìn)行數(shù)據(jù)同步等。以及最后清理掉之前備份的舊數(shù)據(jù)目錄:

[root@PXC-Node2 ~]# rm -rf /var/lib/mysql-backup

冷備份的實(shí)際用途:

  • 當(dāng)PXC集群需要增加新節(jié)點(diǎn)時(shí),可以利用冷備份來備份現(xiàn)有節(jié)點(diǎn)的數(shù)據(jù),然后還原到新增的PXC節(jié)點(diǎn)中。讓新上線節(jié)點(diǎn)具有初始數(shù)據(jù),避免在上線后與集群中的節(jié)點(diǎn)進(jìn)行全量的數(shù)據(jù)同步,進(jìn)而觸發(fā)PXC集群的流控機(jī)制,導(dǎo)致影響整個(gè)集群的性能

常見的熱備份方案

經(jīng)過以上小節(jié),現(xiàn)在我們已經(jīng)了解了冷備份和冷還原,從本節(jié)開始我們來學(xué)習(xí)熱備份。熱備份是數(shù)據(jù)庫(kù)運(yùn)行的狀態(tài)下備份數(shù)據(jù),也是難度最大的備份。PXC集群常見的熱備份有LVM和XtraBackup兩種方案。

LVM方案

利用Linux的LVM技術(shù)來實(shí)現(xiàn)熱備份,將MySQL的數(shù)據(jù)目錄放到LVM邏輯卷上,然后通過LVM快照技術(shù)備份邏輯卷的內(nèi)容。第一次備份是全量備份,之后的備份都是增量備份。在還原時(shí),將快照中的數(shù)據(jù)目錄恢復(fù)到y(tǒng)SQL的數(shù)據(jù)目錄即可。

使用LVM這種技術(shù)不僅可以備份MySQL還可以備份MongoDB等其他數(shù)據(jù)庫(kù),但使用LVM做熱備份方案也比較麻煩,因?yàn)樾枰謩?dòng)創(chuàng)建邏輯卷、遷移數(shù)據(jù)目錄、創(chuàng)建快照以及給數(shù)據(jù)庫(kù)加鎖等等,所以LVM并不是常用的熱備份方案。

XtraBackup方案

因?yàn)長(zhǎng)VM的麻煩,所以人們都希望使用專業(yè)的工具去做熱備份,這個(gè)工具就是XtraBackup。XtraBackup是由Percona開源的免費(fèi)數(shù)據(jù)庫(kù)熱備份工具,它能對(duì)InnoDB數(shù)據(jù)庫(kù)和XtraDB存儲(chǔ)引擎的數(shù)據(jù)庫(kù)非阻塞地備份。因?yàn)閄traBackup在備份過程中不會(huì)打斷正在執(zhí)行的事務(wù),而事務(wù)日志中記錄了哪些是備份前寫入的數(shù)據(jù)哪些是備份后寫入的數(shù)據(jù),所以無需加鎖。

另外,XtraBackup提供了對(duì)備份數(shù)據(jù)的壓縮功能,可以節(jié)約備份文件占用的磁盤空間及網(wǎng)絡(luò)帶寬。但XtraBackup在備份使用MyISAM作為存儲(chǔ)引擎的表時(shí)會(huì)加讀鎖,即表中的數(shù)據(jù)可讀但不可寫,不過這也不是問題,之前提到了可以使用聯(lián)機(jī)熱備份的方式來解決加讀鎖的問題。同樣,XtraBackup支持全量備份和增量備份,因?yàn)閄traBackup的方便性,所以一般都是采用XtraBackup來做熱備份方案。

  • 關(guān)于XtraBackup的安裝及使用可以參考我另一篇文章:數(shù)據(jù)庫(kù)熱備份神器 - XtraBackup,這里就不重復(fù)了。

定時(shí)全量熱備份

系統(tǒng)中通常會(huì)同時(shí)存在全量備份和增量備份,以防其中一個(gè)備份出了問題,還有另一個(gè)備份可以使用。由于全量熱備份比較耗時(shí),所以一般不會(huì)經(jīng)常執(zhí)行,會(huì)間隔一段時(shí)間才執(zhí)行一次。例如,每個(gè)月一號(hào)零點(diǎn)執(zhí)行或每周一零點(diǎn)執(zhí)行等。

在Linux中有一個(gè)crontab命令,可以在固定的間隔時(shí)間執(zhí)行指定的系統(tǒng)指令或shell腳本。使用crontab命令結(jié)合shell腳本可以實(shí)現(xiàn)定時(shí)的全量熱備份。

這里就舉例演示一下,首先編寫執(zhí)行全量熱備份的shell腳本如下:

[root@PXC-Node3 ~]# vim full-backup.sh
#!/bin/bash

time=`date "+%Y-%m-%d %H:%M:%S"`
echo '執(zhí)行全量熱備份 '$time

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/fullBackupOfMysql.xbstream

賦予該腳本執(zhí)行權(quán)限:

[root@PXC-Node3 ~]# chmod -R 777 full-backup.sh

最后配置一下crontab即可,例如我這里定義每周一零點(diǎn)執(zhí)行,這樣就實(shí)現(xiàn)了定時(shí)全量熱備份:

[root@PXC-Node3 ~]# crontab -e
# 每周一零點(diǎn)執(zhí)行
0 0 * * 1 /root/full-backup.sh > /home/backup/full-backup.log 2>&1

XtraBackup全量冷還原

上面介紹了全量熱備份后,我們來看下如何將XtraBackup備份的文件進(jìn)行還原。在還原這塊只能冷還原,不存在熱還原,因?yàn)閷?duì)一個(gè)正在運(yùn)行中的數(shù)據(jù)庫(kù)進(jìn)行在線還原操作,而同時(shí)用戶又在讀寫數(shù)據(jù),這就有可能導(dǎo)致數(shù)據(jù)互相覆蓋,使得數(shù)據(jù)庫(kù)的數(shù)據(jù)發(fā)生錯(cuò)亂。

因此,還原這塊就只能是冷還原,之前也介紹過冷還原,只不過使用XtraBackup進(jìn)行冷還原會(huì)更加簡(jiǎn)單,沒有還原冷備份時(shí)那么麻煩。

首先關(guān)閉MySQL服務(wù):

[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刪除了,如果是實(shí)際的運(yùn)行環(huán)境,建議先使用mv重命名需要?jiǎng)h除的目錄,最后還原完備份文件并驗(yàn)證沒有問題后,再使用rm刪除,以避免刪庫(kù)跑路的悲劇發(fā)生

備份文件是經(jīng)過壓縮的,所以需要?jiǎng)?chuàng)建一個(gè)臨時(shí)目錄來存放解壓后的文件:

[root@PXC-Node3 ~]# mkdir /home/backup/temp

然后使用xbstream命令將備份文件解壓至該目錄下:

[root@PXC-Node3 ~]# xbstream -x < /home/backup/fullBackupOfMysql.xbstream -C /home/backup/temp/

因?yàn)閭浞菸募r(shí)進(jìn)行了加密,所以解壓后的文件都是加密的,需要解密備份文件:

[root@PXC-Node3 ~]# innobackupex --decrypt=AES256 --encrypt-key='1K!cNoq\&RUfQsY\&\&LAczTjco' /home/backup/temp
  • Tips:因?yàn)?code>&是特殊字符,所以需要使用\轉(zhuǎn)義一下

由于是熱備份,所以事務(wù)日志中可能會(huì)存在一些未完成的事務(wù),這就需要回滾沒有提交的事務(wù),以及同步已經(jīng)提交的事務(wù)到數(shù)據(jù)文件。執(zhí)行如下命令:

[root@PXC-Node3 ~]# innobackupex --apply-log /home/backup/temp

完成以上步驟后,就可以使用以下命令對(duì)備份文件進(jìn)行還原:

[root@PXC-Node3 ~]# innobackupex --defaults-file=/etc/my.cnf --copy-back /home/backup/temp

接著給還原后的目錄文件賦予mysql用戶權(quán)限:

[root@PXC-Node3 ~]# chown -R mysql:mysql /var/lib/mysql/*

到此為止就完成了冷還原,最后啟動(dòng)MySQL服務(wù)并自行驗(yàn)證下數(shù)據(jù)是否正常即可:

[root@PXC-Node3 ~]# systemctl start mysqld

增量熱備份

增量熱備份必須以全量熱備份為基礎(chǔ)進(jìn)行備份,所以在了解了XtraBackup的全量熱備份和全量冷還原后,接下來就可以實(shí)踐XtraBackup的增量熱備份了。

注意事項(xiàng):

  • 無論全量熱備份使用了流式壓縮還是內(nèi)容加密,都必須解壓或解密成普通的備份目錄
  • 增量熱備份也同樣可以使用流式壓縮和內(nèi)容加密

之前演示冷還原的時(shí)候已經(jīng)對(duì)全量備份的文件進(jìn)行了解壓縮和內(nèi)容解密,所以這里以/home/backup/temp/備份目錄為例,增量熱備份命令如下:

[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/temp/ --incremental /home/backup/increment
  • --incremental-basedir:指定全量備份文件所存儲(chǔ)的目錄,即基于哪個(gè)全量備份進(jìn)行增量備份
  • --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-32-41/
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命令對(duì)比一下全量熱備份與增量熱備份的目錄大小:

[root@PXC-Node3 ~]# du -sh /home/backup/temp/
1.6G    /home/backup/temp/   # 全量熱備份的目錄大小
[root@PXC-Node3 ~]# du -sh /home/backup/increment/2020-01-26_17-32-41/
92M /home/backup/increment/2020-01-26_17-32-41/  # 增量熱備份的目錄大小
[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-32-41/ --incremental /home/backup/increment

如果增量備份時(shí)需要使用流式壓縮和內(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-32-41/ --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目錄下

Java程序定時(shí)增量熱備份數(shù)據(jù)庫(kù)

通常我們會(huì)讓增量熱備份作為定時(shí)任務(wù)自動(dòng)進(jìn)行,從而避免人工定點(diǎn)去操作,以節(jié)省不必要的工作量。在全量熱備份時(shí)介紹了使用Linux的crontab命令來實(shí)現(xiàn)shell腳本的定時(shí)執(zhí)行,而一些主流的編程語言也都基本具備實(shí)現(xiàn)定時(shí)任務(wù)的框架或類庫(kù)。

這里以Java為例,在Java的生態(tài)中,有Quartz和Spring框架可以實(shí)現(xiàn)定時(shí)任務(wù),同樣也是使用Cron表達(dá)式語法。但Java的Cron表達(dá)式可以精確到秒,這一點(diǎn)與Linux的Cron表達(dá)式有所不同。

由于Quartz稍微復(fù)雜些,為了簡(jiǎn)單起見這里就以Spring為例。首先創(chuàng)建一個(gè)Spring Boot工程,pom.xml中的依賴項(xiàng)如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

在引導(dǎo)類上添加@EnableScheduling注解,以開啟定時(shí)調(diào)度功能:

@EnableScheduling
@SpringBootApplication
public class IncrementBackupApplication {
    ...
}

在Linux上創(chuàng)建一個(gè)文件,用于記錄每次增量熱備份時(shí)基于哪個(gè)目錄去備份。例如在第一次增量熱備份時(shí)是基于全量熱備份的目錄進(jìn)行備份的,而在這之后的增量熱備份則是基于上一次增量熱備份的目錄進(jìn)行備份:

[root@PXC-Node3 ~]# echo '/home/backup/temp/' > /home/backup/increment-backup.cnf

然后編寫實(shí)現(xiàn)定時(shí)執(zhí)行增量熱備份的Java類:

package com.example.incrementbackup.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 增量熱備份定時(shí)任務(wù)
 *
 * @author 01
 * @date 2020-01-26
 **/
@Slf4j
@Component
public class IncrementBackupTask {

    /**
     * 每分鐘執(zhí)行一次增量熱備份
     * 當(dāng)然實(shí)際情況不會(huì)設(shè)置這么短的間隔時(shí)間
     */
    @Scheduled(cron = "0 */1 * * * *")
    public void backup() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH_mm_ss");
        String folderName = LocalDateTime.now().format(formatter);
        String configPath = "/home/backup/increment-backup.cnf";

        try (FileReader fileReader = new FileReader(configPath);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            String basedir = bufferedReader.readLine();
            String cmd = getCmd(basedir, folderName);
            log.info("開始進(jìn)行增量熱備份. 執(zhí)行的命令:{}", cmd);
            // 執(zhí)行增量熱備份命令
            Process process = Runtime.getRuntime().exec(cmd);
            // 等待命令執(zhí)行完成
            process.waitFor();

            try (FileWriter fileWriter = new FileWriter(configPath);
                 BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
                // 更新下次增量備份所使用的basedir路徑
                bufferedWriter.write("/home/backup/increment/" + folderName);
                log.info("增量熱備份結(jié)束");
            }
        } catch (IOException | InterruptedException e) {
            log.error("", e);
        }
    }

    /**
     * 拼裝 innobackupex 命令參數(shù)
     */
    private String getCmd(String basedir, String folderName) {
        String cmd = "innobackupex --defaults-file=/etc/my.cnf " +
                "--user=admin --password=Abc_123456 " +
                "--incremental-basedir=%s --no-timestamp " +
                "--incremental /home/backup/increment/%s";

        return String.format(cmd, basedir, folderName);
    }
}

完成以上代碼的編寫后,使用maven將項(xiàng)目打成jar包,然后將該jar包上傳到Linux中,通過java -jar命令執(zhí)行。如下:

[root@PXC-Node3 ~]# java -jar increment-backup-0.0.1-SNAPSHOT.jar

執(zhí)行過程中輸出的日志信息如下:
關(guān)于數(shù)據(jù)庫(kù)的各種備份與還原姿勢(shì)詳解

等待備份結(jié)束后,可以看到increment-backup.cnf文件的內(nèi)容也更新了:

[root@PXC-Node3 ~]# cat /home/backup/increment-backup.cnf
/home/backup/increment/2020-01-26_21_06_00
[root@PXC-Node3 ~]# 

生成的備份目錄結(jié)構(gòu)也是正常的:

[root@PXC-Node3 ~]# ls /home/backup/increment/2020-01-26_21_12_00
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 ~]# 

到此為止,我們就使用Java語言實(shí)現(xiàn)了定時(shí)增量熱備份數(shù)據(jù)庫(kù)。之所以介紹如何使用編程語言來實(shí)現(xiàn),是因?yàn)閷?shí)際企業(yè)應(yīng)用中,可能會(huì)有一些較為復(fù)雜或個(gè)性化的需求,單純使用shell腳本是無法實(shí)現(xiàn)的。例如要求備份完成后發(fā)送郵件或短信通知相關(guān)人員,又或者要求可以在UI上控制定時(shí)執(zhí)行的間隔時(shí)間等等。這種需求都得使用編程語言去定制化開發(fā)才能實(shí)現(xiàn)。


增量冷還原

經(jīng)過以上小節(jié)可以得知增量熱備份僅備份新數(shù)據(jù),并且生成的備份目錄體積也要比全量熱備份生成的目錄體積要小很多。那么XtraBackup要如何將增量備份的數(shù)據(jù)還原到數(shù)據(jù)庫(kù)呢?其實(shí)也很簡(jiǎn)單,就是先將增量熱備份的數(shù)據(jù)與全量熱備份的數(shù)據(jù)合并,然后基于合并后的備份數(shù)據(jù)去還原即可。

增量熱備份可以有很多個(gè)備份點(diǎn),因?yàn)槌谝淮卧隽繜醾浞萃?,其余的增量熱備份都是基于上一次增量熱備份進(jìn)行的。所以在還原的時(shí)候也可以選擇任意一個(gè)備份點(diǎn)去還原,但事務(wù)日志的處理步驟與全量冷還原不一樣。

在之前演示全量冷還原的時(shí)候,有一個(gè)處理事務(wù)日志的步驟,同樣增量冷還原也有這個(gè)步驟,但是有些差異。上面提到增量熱備份是可以有多個(gè)備份點(diǎn)的,那么在還原某一個(gè)備份點(diǎn)時(shí)就需要處理該備份點(diǎn)及其之前備份點(diǎn)的事務(wù)日志,否則就會(huì)出現(xiàn)數(shù)據(jù)混亂的情況。如下圖,有三個(gè)備份點(diǎn):
關(guān)于數(shù)據(jù)庫(kù)的各種備份與還原姿勢(shì)詳解

例如,當(dāng)還原“增量備份1”時(shí),需要先處理其前一個(gè)備份點(diǎn)的事務(wù)日志,即圖中的“全量熱備份”。接著再處理“增量備份1”這個(gè)備份點(diǎn)的事務(wù)日志,然后合并“增量備份1”的數(shù)據(jù)到“全量熱備份”中。這樣才能保證多個(gè)備份點(diǎn)合并到全量備份點(diǎn)后的數(shù)據(jù)是一致的,最后還原“全量熱備份”中的數(shù)據(jù)即可。

再例如,要還原的是“增量備份2”,那么就得先處理“全量熱備份”,然后處理“增量備份1”,接著處理“增量備份2”,按從前往后的順序依次將這三個(gè)備份點(diǎn)的事務(wù)日志都給處理了后,才能合并備份點(diǎn)的數(shù)據(jù)到全量備份中,最后還原“全量熱備份”中的數(shù)據(jù)。其余則以此類推......

接下來實(shí)操一下增量冷還原,這里有三個(gè)與上圖對(duì)應(yīng)的備份點(diǎn)目錄:

/home/backup/temp/  # 全量熱備份
/home/backup/increment/2020-01-27_10-11-24/  # 增量備份1
/home/backup/increment/2020-01-27_10-15-11/  # 增量備份2

因?yàn)槭抢溥€原,所以得先關(guān)閉MySQL服務(wù):

[root@PXC-Node3 ~]# systemctl stop mysqld

在本例中要還原的是“增量備份2”這個(gè)備份點(diǎn)的數(shù)據(jù),按照之前的說明,首先處理全量備份點(diǎn)的事務(wù)日志,執(zhí)行如下命令:

[root@PXC-Node3 ~]# innobackupex --apply-log --redo-only /home/backup/temp/
  • --redo-only:指定不回滾未提交的事務(wù),因?yàn)橄聜€(gè)備份點(diǎn)的事務(wù)日志里可能會(huì)提交該備份點(diǎn)未提交的事務(wù)。如果回滾了就會(huì)導(dǎo)致下個(gè)備份點(diǎn)無法正常提交

然后處理“增量備份1”的事務(wù)日志,并將"增量備份1"的數(shù)據(jù)合并到全量備份點(diǎn)上:

[root@PXC-Node3 ~]# innobackupex --apply-log --redo-only /home/backup/temp/ --incremental-dir=/home/backup/increment/2020-01-27_10-11-24/
  • --incremental-dir:指定要合并到全量備份的增量備份目錄

接著處理“增量備份2”的事務(wù)日志,并將"增量備份2"的數(shù)據(jù)合并到全量備份點(diǎn)上。由于只還原到“增量備份2”這個(gè)備份點(diǎn),所以就不需要加上--redo-only參數(shù)了,因?yàn)闆]有下個(gè)備份點(diǎn)了:

[root@PXC-Node3 ~]# innobackupex --apply-log /home/backup/temp/ --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/temp/  # 注意這里指定的是全量備份點(diǎn)的目錄

接著給還原后的目錄文件賦予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/*

到此為止還原就完成了,最后啟動(dòng)MySQL服務(wù)并自行驗(yàn)證下數(shù)據(jù)是否正常即可:

[root@PXC-Node3 ~]# systemctl start mysqld
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI