91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

關于數據庫的各種備份與還原姿勢詳解

發布時間:2020-02-14 11:09:20 來源:網絡 閱讀:549 作者:ZeroOne01 欄目:MySQL數據庫

數據庫的冷備份與熱備份

數據導出不完全等于數據備份:

  • 數據導出是指將數據庫中的數據逆向成SQL語句進行導出,所以導出的是SQL文件。通常用作把數據從一個系統遷移到另一個系統,目的是屏蔽系統之間的差異性
  • 數據備份是指將數據庫中數據存儲的相關文件進行拷貝,用于保存一個數據庫的全部物理數據,所以備份后的數據與原本數據在細節及狀態上都是完全一致的。不會像SQL那樣在使用了一些函數的情況下,可能會在不同的時間點或不同的系統上產生不一樣的結果

冷備份與熱備份:

  • 冷備份:在數據庫已經關閉的情況下,對數據的備份稱作冷備份
  • 熱備份:與冷備份相反,在數據庫節點不停機的狀態下進行的備份被稱作熱備份

冷備份的限制:

  • 數據庫必須停機備份,這對一些線上數據庫是無法接受的
  • 備份的數據文件非常占用存儲空間,并且不支持增量備份
  • 冷備份是備份所有的數據文件和日志文件,所以無法單獨備份某個邏輯庫和數據表

聯機冷備份:

單節點的數據庫在冷備份時需要停機,這就會對業務系統產生影響。為了解決這個問題,我們可以組建集群然后挑選集群中的一個節點進行停機冷備份。由于集群中還有其他節點在運行,所以不必擔心影響正在運行的系統。等備份結束之后再啟動該節點,這樣就能解決停機備份帶來的影響

熱備份的限制:

  • 數據庫在熱備份的時候會全局加讀鎖,備份期間節點只能讀取數據不能寫入數據

聯機熱備份:

同樣的方式,為了避免全局加鎖,我們可以挑選集群中的一個節點與其他節點解除數據同步關系后進行熱備份。等待備份完成后,再去恢復與集群中其他節點的數據同步關系。這樣在備份過程中就只有該節點會加讀鎖,其他節點不會受到影響

聯機熱備份與聯機冷備份該如何選擇:

建議選擇聯機熱備份,因為熱備份可以選擇全量備份或增量備份。而冷備份只能選擇全量備份,當后期數據量很大的時候,冷備份需要耗費很多的時間,并且由于是全量備份也需要占用更多的存儲空間。熱備份只有在第一次備份的時候需要選擇全量備份,后續備份只需要增量備份新數據即可。 因此,熱備份在存儲空間的占用及備份耗費的時間上都優于冷備份


實踐聯機冷備份

認識MySQL中與數據相關的文件

上一小節提到了數據備份是指將數據庫中數據存儲的相關文件進行拷貝,而這些文件有很多,所以讓我們來簡單認識下MySQL中與數據相關的文件。

首先是組成邏輯庫的文件,在MySQL中一個邏輯庫實際由多個文件組成,其結構如下:
關于數據庫的各種備份與還原姿勢詳解

  • OPT文件:定義字符集和字符集的排序規則,該文件是一個文本文件
  • FRM文件:這是數據表的定義文件,包含了數據表的結構信息。無論數據表使用的什么存儲引擎,每一個數據表的定義文件一定是FRM文件
  • ISL文件:該文件只有創建了表分區才會出現,它存儲著表分區數據文件所在的路徑
  • MyISAM:
    • MYD文件:MyISAM的數據文件
    • MYI文件:MyISAM的索引文件
  • InnoDB:
    • IBD文件:InnoDB的索引及數據文件,該文件是一個二進制文件

FRM文件在很多情況下都會被用到,例如數據庫在執行SQL語句之前,先會審查SQL語句中用到的一些字段是否在FRM文件中定義了。或者數據庫在優化SQL語句時,通過FRM文件判斷where子句中的字段是否是主鍵列或索引列等。因為FRM文件經常會被使用,所以該文件是一個二進制文件

MySQL中的其他文件:

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

數據文件的碎片整理

數據文件中的碎片是什么:

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

MySQL的數據文件一直存在著碎片化問題,MySQL之所以不會自動整理碎片縮減數據文件的體積,是因為這個整理過程是會鎖表的。如果每刪除一條數據就鎖表整理碎片,那么勢必會對數據表的讀寫造成很大的影響。不過MySQL在寫入新數據時,會優先將其寫入碎片空間,所以數據文件中的碎片空間對日常運行沒有什么影響。

但是對于數據庫備份這個場景來說,如果數據文件中存在著大量的碎片,就會導致實際有意義的數據沒多少,而數據文件的體積又很大。這對備份來說就很占用存儲空間和傳輸帶寬,所以在進行備份之前,需要對數據文件的碎片進行一個整理,盡量縮減數據文件的體積。

MySQL中整理數據文件碎片的SQL語句如下:

alter table ${table_name} engine=InnoDB;

需要注意的是,在執行該SQL之前,記得先將用于備份的數據庫節點的binlog給關掉。避免binlog中記錄了該SQL,導致在節點備份完成恢復到集群后,其他節點同步了該SQL出現整個集群鎖表的情況。所以需要注釋掉MySQL配置文件中的以下兩個參數,在備份完成后再打開:

# log_bin
# log_slave_updates

冷備份

在前面介紹了一些前置知識后,本小節就逐步演示一下如何實踐聯機冷備份。我這里事先準備了一個由三個節點組成的PXC集群:
關于數據庫的各種備份與還原姿勢詳解

首先挑選集群中的任意一個節點作為備份節點,然后停止該節點:

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

編輯配置文件,注釋binlog相關參數:

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

#log-bin
#log_slave_updates

然后注釋PXC集群相關參數:

[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

修改完畢后,啟動MySQL服務,此時該節點就退出了PXC集群:

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

該節點的數據文件有1.1個G:

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

本示例中是對test庫進行備份,所以在進行備份之前,需要對test庫下所有的表進行碎片整理。由于表比較多,我這里編寫了一個簡單的Java程序來實現:

import com.mysql.jdbc.Driver;

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

/**
 * 數據表碎片整理
 *
 * @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服務,因為冷備份需要停機:

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

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

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

如果創建了表分區,并且將表分區映射到了其他目錄上,那么就還需要對表分區進行打包。例如我這里有兩個表分區,分別映射到了/mnt/p0/data//mnt/p1/data/目錄,所以執行的命令如下:

[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/

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


冷還原

演示了如何冷備份后,接下來則演示如何將備份文件冷還原到其他的PXC節點上。首先將備份文件傳輸到需要還原的節點上,可以使用scprsync命令在Linux系統之間傳輸文件,如下示例:

[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

還原節點接收到的備份文件如下:

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

除此之外還需要進行一些準備工作,因為備份節點是存在表分區的,并且映射了相應的數據目錄,若還原節點不存在則需要創建。如下示例:

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

由于是冷還原,所以和冷備份一樣也需要先停止還原節點:

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

還原MySQL的數據目錄,命令如下:

# 先備份原本的數據目錄,以防萬一
[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/

然后是還原表分區數據目錄:

[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重復的話,該節點是無法啟動的:

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

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

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

safe_to_bootstrap: 0

到此就算是還原完成了,啟動MySQL服務即可:

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

剩下就是自行驗證下該節點的數據是否正確還原了,能否與集群中其他節點進行數據同步等。以及最后清理掉之前備份的舊數據目錄:

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

冷備份的實際用途:

  • 當PXC集群需要增加新節點時,可以利用冷備份來備份現有節點的數據,然后還原到新增的PXC節點中。讓新上線節點具有初始數據,避免在上線后與集群中的節點進行全量的數據同步,進而觸發PXC集群的流控機制,導致影響整個集群的性能

常見的熱備份方案

經過以上小節,現在我們已經了解了冷備份和冷還原,從本節開始我們來學習熱備份。熱備份是數據庫運行的狀態下備份數據,也是難度最大的備份。PXC集群常見的熱備份有LVM和XtraBackup兩種方案。

LVM方案

利用Linux的LVM技術來實現熱備份,將MySQL的數據目錄放到LVM邏輯卷上,然后通過LVM快照技術備份邏輯卷的內容。第一次備份是全量備份,之后的備份都是增量備份。在還原時,將快照中的數據目錄恢復到ySQL的數據目錄即可。

使用LVM這種技術不僅可以備份MySQL還可以備份MongoDB等其他數據庫,但使用LVM做熱備份方案也比較麻煩,因為需要手動創建邏輯卷、遷移數據目錄、創建快照以及給數據庫加鎖等等,所以LVM并不是常用的熱備份方案。

XtraBackup方案

因為LVM的麻煩,所以人們都希望使用專業的工具去做熱備份,這個工具就是XtraBackup。XtraBackup是由Percona開源的免費數據庫熱備份工具,它能對InnoDB數據庫和XtraDB存儲引擎的數據庫非阻塞地備份。因為XtraBackup在備份過程中不會打斷正在執行的事務,而事務日志中記錄了哪些是備份前寫入的數據哪些是備份后寫入的數據,所以無需加鎖。

另外,XtraBackup提供了對備份數據的壓縮功能,可以節約備份文件占用的磁盤空間及網絡帶寬。但XtraBackup在備份使用MyISAM作為存儲引擎的表時會加讀鎖,即表中的數據可讀但不可寫,不過這也不是問題,之前提到了可以使用聯機熱備份的方式來解決加讀鎖的問題。同樣,XtraBackup支持全量備份和增量備份,因為XtraBackup的方便性,所以一般都是采用XtraBackup來做熱備份方案。

  • 關于XtraBackup的安裝及使用可以參考我另一篇文章:數據庫熱備份神器 - XtraBackup,這里就不重復了。

定時全量熱備份

系統中通常會同時存在全量備份和增量備份,以防其中一個備份出了問題,還有另一個備份可以使用。由于全量熱備份比較耗時,所以一般不會經常執行,會間隔一段時間才執行一次。例如,每個月一號零點執行或每周一零點執行等。

在Linux中有一個crontab命令,可以在固定的間隔時間執行指定的系統指令或shell腳本。使用crontab命令結合shell腳本可以實現定時的全量熱備份。

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

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

time=`date "+%Y-%m-%d %H:%M:%S"`
echo '執行全量熱備份 '$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

賦予該腳本執行權限:

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

最后配置一下crontab即可,例如我這里定義每周一零點執行,這樣就實現了定時全量熱備份:

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

XtraBackup全量冷還原

上面介紹了全量熱備份后,我們來看下如何將XtraBackup備份的文件進行還原。在還原這塊只能冷還原,不存在熱還原,因為對一個正在運行中的數據庫進行在線還原操作,而同時用戶又在讀寫數據,這就有可能導致數據互相覆蓋,使得數據庫的數據發生錯亂。

因此,還原這塊就只能是冷還原,之前也介紹過冷還原,只不過使用XtraBackup進行冷還原會更加簡單,沒有還原冷備份時那么麻煩。

首先關閉MySQL服務:

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

清空數據目錄及表分區的數據目錄:

[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刪除了,如果是實際的運行環境,建議先使用mv重命名需要刪除的目錄,最后還原完備份文件并驗證沒有問題后,再使用rm刪除,以避免刪庫跑路的悲劇發生

備份文件是經過壓縮的,所以需要創建一個臨時目錄來存放解壓后的文件:

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

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

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

因為備份文件時進行了加密,所以解壓后的文件都是加密的,需要解密備份文件:

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

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

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

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

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

接著給還原后的目錄文件賦予mysql用戶權限:

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

到此為止就完成了冷還原,最后啟動MySQL服務并自行驗證下數據是否正常即可:

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

增量熱備份

增量熱備份必須以全量熱備份為基礎進行備份,所以在了解了XtraBackup的全量熱備份和全量冷還原后,接下來就可以實踐XtraBackup的增量熱備份了。

注意事項:

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

之前演示冷還原的時候已經對全量備份的文件進行了解壓縮和內容解密,所以這里以/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:指定全量備份文件所存儲的目錄,即基于哪個全量備份進行增量備份
  • --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命令對比一下全量熱備份與增量熱備份的目錄大小:

[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

如果增量備份時需要使用流式壓縮和內容加密,則添加相關參數即可。如下示例:

[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:這里的./表示將增量備份所有的內容都寫到流式壓縮文件里,壓縮文件則存放在/home/backup/increment目錄下

Java程序定時增量熱備份數據庫

通常我們會讓增量熱備份作為定時任務自動進行,從而避免人工定點去操作,以節省不必要的工作量。在全量熱備份時介紹了使用Linux的crontab命令來實現shell腳本的定時執行,而一些主流的編程語言也都基本具備實現定時任務的框架或類庫。

這里以Java為例,在Java的生態中,有Quartz和Spring框架可以實現定時任務,同樣也是使用Cron表達式語法。但Java的Cron表達式可以精確到秒,這一點與Linux的Cron表達式有所不同。

由于Quartz稍微復雜些,為了簡單起見這里就以Spring為例。首先創建一個Spring Boot工程,pom.xml中的依賴項如下:

<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>

在引導類上添加@EnableScheduling注解,以開啟定時調度功能:

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

在Linux上創建一個文件,用于記錄每次增量熱備份時基于哪個目錄去備份。例如在第一次增量熱備份時是基于全量熱備份的目錄進行備份的,而在這之后的增量熱備份則是基于上一次增量熱備份的目錄進行備份:

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

然后編寫實現定時執行增量熱備份的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;

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

    /**
     * 每分鐘執行一次增量熱備份
     * 當然實際情況不會設置這么短的間隔時間
     */
    @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("開始進行增量熱備份. 執行的命令:{}", cmd);
            // 執行增量熱備份命令
            Process process = Runtime.getRuntime().exec(cmd);
            // 等待命令執行完成
            process.waitFor();

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

    /**
     * 拼裝 innobackupex 命令參數
     */
    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將項目打成jar包,然后將該jar包上傳到Linux中,通過java -jar命令執行。如下:

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

執行過程中輸出的日志信息如下:
關于數據庫的各種備份與還原姿勢詳解

等待備份結束后,可以看到increment-backup.cnf文件的內容也更新了:

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

生成的備份目錄結構也是正常的:

[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語言實現了定時增量熱備份數據庫。之所以介紹如何使用編程語言來實現,是因為實際企業應用中,可能會有一些較為復雜或個性化的需求,單純使用shell腳本是無法實現的。例如要求備份完成后發送郵件或短信通知相關人員,又或者要求可以在UI上控制定時執行的間隔時間等等。這種需求都得使用編程語言去定制化開發才能實現。


增量冷還原

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

增量熱備份可以有很多個備份點,因為除第一次增量熱備份外,其余的增量熱備份都是基于上一次增量熱備份進行的。所以在還原的時候也可以選擇任意一個備份點去還原,但事務日志的處理步驟與全量冷還原不一樣。

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

例如,當還原“增量備份1”時,需要先處理其前一個備份點的事務日志,即圖中的“全量熱備份”。接著再處理“增量備份1”這個備份點的事務日志,然后合并“增量備份1”的數據到“全量熱備份”中。這樣才能保證多個備份點合并到全量備份點后的數據是一致的,最后還原“全量熱備份”中的數據即可。

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

接下來實操一下增量冷還原,這里有三個與上圖對應的備份點目錄:

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

因為是冷還原,所以得先關閉MySQL服務:

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

在本例中要還原的是“增量備份2”這個備份點的數據,按照之前的說明,首先處理全量備份點的事務日志,執行如下命令:

[root@PXC-Node3 ~]# innobackupex --apply-log --redo-only /home/backup/temp/
  • --redo-only:指定不回滾未提交的事務,因為下個備份點的事務日志里可能會提交該備份點未提交的事務。如果回滾了就會導致下個備份點無法正常提交

然后處理“增量備份1”的事務日志,并將"增量備份1"的數據合并到全量備份點上:

[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”的事務日志,并將"增量備份2"的數據合并到全量備份點上。由于只還原到“增量備份2”這個備份點,所以就不需要加上--redo-only參數了,因為沒有下個備份點了:

[root@PXC-Node3 ~]# innobackupex --apply-log /home/backup/temp/ --incremental-dir=/home/backup/increment/2020-01-27_10-15-11/

與全量冷還原一樣,也需清空數據目錄及表分區的數據目錄:

[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/  # 注意這里指定的是全量備份點的目錄

接著給還原后的目錄文件賦予mysql用戶權限:

[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服務并自行驗證下數據是否正常即可:

[root@PXC-Node3 ~]# systemctl start mysqld
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大连市| 枣阳市| 呼玛县| 寻甸| 文化| 高清| 凤冈县| 冕宁县| 远安县| 德惠市| 满城县| 吐鲁番市| 剑阁县| 苏州市| 收藏| 莒南县| 黔西县| 高尔夫| 肇源县| 海南省| 沿河| 永济市| 林口县| 长汀县| 博白县| 贞丰县| 贺州市| 临沭县| 乌兰察布市| 鹤岗市| 平谷区| 富源县| 湖口县| 齐河县| 大化| 连州市| 益阳市| 五台县| 泌阳县| 祁连县| 滁州市|