使用mysqldump進行資料庫或表的備份非常友善,操作簡單使用靈活,在小資料量的備份和恢複時間可以接受,如果資料量較大,mysqldump恢複的時間會很長而難以接受。
xtrabackup是一款高效的備份工具,備份時并不會影響原資料庫的正常更新。
xtrabackup安裝
官方網站:https://www.percona.com
wget https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.4/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.4-1.el7.x86_64.rpm
wget https://www.percona.com/downloads/percona-toolkit/2.2.19/RPM/percona-toolkit-2.2.19-1.noarch.rpm
yum install ./*.rpm #使用yum自動解決依賴包
備份的實作
-------------------------------------------------------------------------【完全備份】-------------------------------------------------------------------------
# innobackupex --user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/
如果要使用一個最小權限的使用者進行備份,則可基于如下指令建立此類使用者
mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO ’bkpuser’@’localhost’;
mysql> FLUSH PRIVILEGES;
開啟二進制日志,并指定儲存路徑
#vim /etc/my.cnf
[mysqld]
log-bin=/data/mysqlbinlog/mysql-bin.log
#mkdir /data/mysqlbinlog
#chown -R mysql.mysql /data/mysqlbinlog
#systemctl restart mariadb
建立備份檔案所在目錄然後備份
#mkdir /mybackups
#innobackupex --user=root --password=123456 /mybackups/
...
160817 11:52:07 Executing UNLOCK TABLES
160817 11:52:07 All tables unlocked
160817 11:52:07 Backup created in directory \'/mybackups/2016-08-17_11-51-57\'
MySQL binlog position: filename \'mysql-bin.000001\', position \'245\'
160817 11:52:07 [00] Writing backup-my.cnf
160817 11:52:07 [00] ...done
160817 11:52:07 [00] Writing xtrabackup_info
160817 11:52:07 [00] ...done
xtrabackup: Transaction log of lsn (1837553) to (1837553) was copied.
160817 11:52:07 completed OK!
備份完成之後檢視備份目錄
# ls /mybackups/
2016-08-17_11-51-57
# cd 2016-08-17_11-51-57/;ls
backup-my.cnf mydb performance_schema xtrabackup_binlog_info xtrabackup_info
ibdata1
模拟丢失資料
删除資料目錄
#systemctl stop mariadb
#cd /var/lib/mysql/
#rm -rf ./
準備一個完全備份
#innobackupex --apply-log /path/to/BACKUP-DIR
一般情況下,在備份完成後,資料尚且不能用于恢複操作,因為備份的資料可能包含尚未送出的事務或者已經送出但尚未同步至資料檔案中的事務。
是以,此時資料檔案仍處于不一緻的狀态。"準備"的主要作用正是通過復原未送出的事務及同步已經送出的事務至資料檔案也使得資料檔案處于一緻性狀态
隻要當我們需要開始還原的時候才"準備"
#innobackupex --apply-log /mybackups/2016-08-17_11-51-57
...
InnoDB: Setting file \'./ibtmp1\' size to 12 MB. Physically writing the file full; Please wait ...
InnoDB: File \'./ibtmp1\' size is now 12 MB.
InnoDB: 96 redo rollback segment(s) found. 1 redo rollback segment(s) are active.
InnoDB: 32 non-redo rollback segment(s) are active.
InnoDB: Waiting for purge to start
InnoDB: 5.7.13 started; log sequence number 1838101
xtrabackup: starting shutdown with innodb_fast_shutdown = 1
InnoDB: FTS optimize thread exiting.
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 1838120
160817 12:47:42 completed OK!
從一個完全備份中恢複資料
#innobackupex --copy-back /path/to/BACKUP-DIR
注意:恢複不用啟動MySQL
#innobackupex --copy-back /mybackups/2016-08-17_11-51-57/
...
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./school/teacher.frm to /var/lib/mysql/school/teacher.frm
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./xtrabackup_info to /var/lib/mysql/xtrabackup_info
160817 13:11:29 [01] ...done
160817 13:11:29 [01] Copying ./ibtmp1 to /var/lib/mysql/ibtmp1
160817 13:11:29 [01] ...done
160817 13:11:29 completed OK!
還原成功後,檢查并啟動資料庫
檢視MySQL資料目錄,已經恢複回來了
#ls /var/lib/mysql/
ibdata1 ib_logfile0 ib_logfile1 ibtmp1 mydb mysql performance_schema school xtrabackup_info
當資料恢複至DATADIR目錄以後,還需要確定所有資料檔案的屬主和屬組均為正确的使用者,如mysql,否則,在啟動mysqld之前還需要事先修改資料檔案的屬主和屬組。如:
chown -R mysql.mysql /var/lib/mysql/
啟動資料庫,檢查資料
# systemctl start mariadb
-------------------------------------------------------------------------【增量備份】-------------------------------------------------------------------------
建立一個新的完全備份
# innobackupex --user=root --password=123456 /mybackups/
# ls /mybackups/
2016-08-17_11-51-57(上次的wan完全備份,磁盤空間夠用的話可以留着,否則可以删除) 2016-08-17_15-43-49(最新的完全備份)
檢視備份點
# cat /mybackups/2016-08-17_15-43-49/xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 1838120
last_lsn = 1838120
compact = 0
recover_binlog_info = 0
在庫裡寫入新的資料
# mysql -uroot -p123456
MariaDB [(none)]> use school
MariaDB [school]> create table t1(id int);
MariaDB [school]> insert into t1 value(1),(2);
MariaDB [school]> \q
資料有變動了,現在做增量備份
每個InnoDB的頁面都會包含一個LSN資訊,每當相關的資料發生改變,相關的頁面的LSN就會自動增長。這正是InnoDB表可以進行增量備份的基礎。
即innobackupex通過備份上次完全備份之後發生改變的頁面來實作。
# innobackupex --incremental /backup --incremental-basedir=BASEDIR
其中,BASEDIR指的是完全備份所在的目錄,此指令執行結束後,innobackupex指令會在/backup目錄中建立一個新的以時間命名的目錄以存放所有的增量備份資料。
另外,在執行過增量備份之後再一次進行增量備份時,其--incremental-basedir應該指向上一次的增量備份所在的目錄。
需要注意的是,增量備份僅能應用于InnoDB或XtraDB表,對于MyISAM表而言,執行增量備份時其實進行的是完全備份。
# innobackupex --user=root --password=123456 --incremental /mybackups/ --incremental-basedir=/mybackups/2016-08-17_15-43-49/
檢視備份目錄
# ls /mybackups/
2016-08-17_11-51-57 2016-08-17_15-43-49 2016-08-17_16-04-43(增量備份)
檢視備份點
# cat /mybackups/2016-08-17_16-04-43/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1838120 <--------可以看到是從上次完整備份的結束點開始
to_lsn = 1840190
last_lsn = 1840190
compact = 0
recover_binlog_info = 0
再次寫入新的資料
MariaDB [(none)]> create database sellsa;
MariaDB [(none)]> use sellsa;
MariaDB [sellsa]> create table test1(Name char(10));
再做一次增量備份
# innobackupex --user=root --password=123456 --incremental /mybackups/ --incremental-basedir=/mybackups/2016-08-17_16-04-43/(上次增量備份的目錄)
# ls /mybackups/
2016-08-17_11-51-57 2016-08-17_15-43-49 2016-08-17_16-04-43(增量備份) 2016-08-17_16-14-01(增量備份)
檢視備份點
# cat /mybackups/2016-08-17_16-14-01/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1840190 <--------可以看到是從上次增量備份的結束點開始
to_lsn = 1841816
last_lsn = 1841816
compact = 0
recover_binlog_info = 0
當我們再次寫入資料,然後沒來得及做增量備份,資料庫沒了,此刻該怎麼辦?
再次寫入資料
MariaDB [(none)]> use school;
MariaDB [school]> insert into t1 values(3),(4);
假如現在資料庫崩潰了或者磁盤壞掉了,沒有來得及做增量備份,我們現在模拟把資料目錄清掉
# systemctl stop mariadb
# cd /var/lib/mysql/
# rm -rf ./*
***************************************************************************************************
"準備"增量備份與準備完全備份有着一些不同,尤其要注意的是:
1)需要在每個備份(包括完全和各個增量備份)上,将已經送出的事務進行"重放",所有的備份資料将合并到完全備份上
2)基于所有的備份将未送出的事務進行"復原"
于是,操作就變成了:
# innobackupex --apply-log --redo-only BASE-DIR(完全備份所在目錄)
接着執行一個增量備份:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1(第一次增量備份所在目錄)
而後是第二個增量:
# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-2(第二次增量備份所在目錄)
以此類推
***************************************************************************************************
# innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/
# innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/ --incremental-dir=/mybackups/2016-08-17_16-04-43/
# innobackupex --apply-log --redo-only /mybackups/2016-08-17_15-43-49/ --incremental-dir=/mybackups/2016-08-17_16-14-01/
我們去檢視合并後的備份點
# cat /mybackups/2016-08-17_16-14-01/xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1840190 <-----------
to_lsn = 1841816
last_lsn = 1841816
compact = 0
recover_binlog_info = 0
現在我們還原這個合并後的完全備份
# innobackupex --copy-back /mybackups/2016-08-17_15-43-49/
更改屬主、屬組
# chown -R mysql.mysql /var/lib/mysql/
因為最後沒有增量備份,是以我們需要用到二進制日志及時點恢複
檢視最後一次增量備份的二進制日志位置點資訊
# cat /mybackups/2016-08-17_16-14-01/xtrabackup_binlog_info
mysql-bin.000005 707
把這個點以後的二進制日志導出來
# mysqlbinlog --start-position=707 /data/mysqlbinlog/mysql-bin.000005 >/tmp/inc.sql
啟動資料庫
# systemctl start mariadb
#進入MySQL,設定這個會話不記錄二進制日志
MariaDB [(none)]> set session sql_log_bin=0;
導入剛剛的日志檔案
MariaDB [(none)]> source /tmp/inc.sql;
#設定會記錄二進制日志
MariaDB [school]> set session sql_log_bin=1;
-------------------------------------------------------------------------【導入或導出單張表】-------------------------------------------------------------------------
預設情況下,InnoDB表不能通過直接複制表檔案的方式在mysql伺服器之間進行移植,即便使用了innodb_file_per_table選項。而使用Xtrabackup工具可以實作此種功能,不過,此時需要“導出”表的mysql伺服器啟用了innodb_file_per_table選項(嚴格來說,是要“導出”的表在其建立之前,mysql伺服器就啟用了innodb_file_per_table選項),并且“導入”表的伺服器同時啟用了innodb_file_per_table和innodb_expand_import選項。
(1)“導出”表
導出表是在備份的prepare階段進行的,是以,一旦完全備份完成,就可以在prepare過程中通過--export選項将某表導出了:
# innobackupex --apply-log --export /path/to/backup
此指令會為每個innodb表的表空間建立一個以.exp結尾的檔案,這些以.exp結尾的檔案則可以用于導入至其它伺服器。(拷貝完,注意檔案的權限,否則導入表的時候會失敗)
(2)“導入”表
要在mysql伺服器上導入來自于其它伺服器的某innodb表,需要先在目前伺服器上建立一個跟原表表結構一緻的表,而後才能實作将表導入:
mysql> CREATE TABLE mytable (...) ENGINE=InnoDB;
然後将此表的表空間删除:
mysql> ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
接下來,将來自于“導出”表的伺服器的mytable表的mytable.ibd和mytable.exp檔案複制到目前伺服器的資料目錄,然後使用如下指令将其“導入”:
mysql> ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;
-------------------------------------------------------------------------【使用Xtrabackup對資料庫進行部分備份】-------------------------------------------------------------------------
Xtrabackup也可以實作部分備份,即隻備份某個或某些指定的資料庫或某資料庫中的某個或某些表。但要使用此功能,必須啟用innodb_file_per_table選項,即每張表儲存為一個獨立的檔案。同時,其也不支援--stream選項,即不支援将資料通過管道傳輸給其它程式進行處理。
此外,還原部分備份跟還原全部資料的備份也有所不同,即你不能通過簡單地将prepared的部分備份使用--copy-back選項直接複制回資料目錄,而是要通過導入表的方向來實作還原。當然,有些情況下,部分備份也可以直接通過--copy-back進行還原,但這種方式還原而來的資料多數會産生資料不一緻的問題,是以,無論如何不推薦使用這種方式。
(1)建立部分備份
建立部分備份的方式有三種:正規表達式(--include), 枚舉表檔案(--tables-file)和列出要備份的資料庫(--databases)。
(a)使用--include
使用--include時,要求為其指定要備份的表的完整名稱,即形如databasename.tablename,如:
# innobackupex --include=\'^mageedu[.]tb1\' /path/to/backup
(b)使用--tables-file
此選項的參數需要是一個檔案名,此檔案中每行包含一個要備份的表的完整名稱;如:
# echo -e \'mageedu.tb1\nmageedu.tb2\' > /tmp/tables.txt
# innobackupex --tables-file=/tmp/tables.txt /path/to/backup
(c)使用--databases
此選項接受的參數為資料名,如果要指定多個資料庫,彼此間需要以空格隔開;同時,在指定某資料庫時,也可以隻指定其中的某張表。此外,此選項也可以接受一個檔案為參數,檔案中每一行為一個要備份的對象。如:
# innobackupex --databases="mageedu testdb" /path/to/backup
(2)整理(preparing)部分備份
prepare部分備份的過程類似于導出表的過程,要使用--export選項進行:
# innobackupex --apply-log --export /pat/to/partial/backup
此指令執行過程中,innobackupex會調用xtrabackup指令從資料字典中移除缺失的表,是以,會顯示出許多關于“表不存在”類的警告資訊。同時,也會顯示出為備份檔案中存在的表建立.exp檔案的相關資訊。
(3)還原部分備份
還原部分備份的過程跟導入表的過程相同。當然,也可以通過直接複制prepared狀态的備份直接至資料目錄中實作還原,不要此時要求資料目錄處于一緻狀态。
