測試準備 一、安裝xtrabackup工具 如下測試安裝xtrabackup備份恢復工具的二進制包,進行測試。安裝的路徑爲mysql安裝路徑,本次測試mysql的安裝路徑爲:/home/q/percona-server/。 tar -xzf percona-xtraback-2.0.0-x86-64.tar.gzcp percona-xtrabackup-2.0.0/bin/* /home/q/percona-server/bin 二、建立備份用戶 建立備份用戶backup@localhost,xtraback只能用於本地操做,故只受權本地操做。 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO backup@localhost; 三、聲明PATH環境變量 爲xtrabackup備份恢復工具添加到PATH路徑中。 export PATH=$PATH:/home/q/percona-server/bin 四、建立測試庫 建立測試庫backup_test,測試表test。 mysql -uroot -S/tmp/mysql.sock -e'create database backup_test;'mysql -uroot -S/tmp/mysql.sock -e'create table backup_test.test (id int);'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test.test values(1),(2),(3),(4),(5);' 測試innodb 一、全備份測試 全備份測試主要經過測試如下幾個場景,對數據備份和恢復進行驗證。 1)備份全庫,恢復進行測試。 進行全庫備份: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/* 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,備份恢復正確。 2)修改表結構,備份全庫,恢復進行測試。 修改數據庫表結構: mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test add name varchar(20) default "null";' 進行全庫備份: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/* 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,備份恢復正確。 3)備份某個庫,恢復測試 備份backup_test庫 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --user=backup backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 修改當前數據文件: mv /home/q/percona-server/data /home/q/percona-server/databakmkdir /home/q/percona-server/data 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --database=backup_test --user=backup backup/<DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --database=backup_test --user=backup backup/<DATE_TIME>cp /home/q/percona-server/databak/* /home/q/percona-server/data(僅拷貝不在data中的文件) 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,備份單個庫沒有問題。存在的不足是,恢復的時候,數據目錄必須爲空。也就是說,在恢復階段,須要將現有的數據目錄更名爲臨時目錄;在恢復以後,將原數據目錄(現臨時目錄)下的其餘庫的內容拷貝到數據目錄下便可。 4)備份單個表,恢復測試 備份backup_test庫 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test --user=backup backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 修改當前數據文件: mv /home/q/percona-server/data /home/q/percona-server/databakmkdir /home/q/percona-server/data 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,備份單個表沒有問題。存在的不足是,恢復的時候,數據目錄必須爲空。也就是說,在恢復階段,須要將現有的數據目錄更名爲臨時目錄;在恢復以後,將原數據目錄(現臨時目錄)下的其餘庫的內容拷貝到數據目錄下便可。 5)innodb_file_per_table參數驗證 修改配置文件 在配置文件中添加innodb_file_per_table配置參數。 重啓數據庫server kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ')mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf & 建立測試庫backup_test mysql -uroot -S/tmp/mysql.sock -e'create database backup_test;'mysql -uroot -S/tmp/mysql.sock -e'create table backup_test.test (id int);'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test.test values(1),(2),(3),(4),(5);' 備份backup_test庫 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test --user=backup backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 修改當前數據文件: mv /home/q/percona-server/data /home/q/percona-server/databakmkdir /home/q/percona-server/data 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,備份單個庫沒有問題。存在的不足是,恢復的時候,數據目錄必須爲空。也就是說,在恢復階段,須要將現有的數據目錄更名爲臨時目錄;在恢復以後,將原數據目錄(現臨時目錄)下的其餘庫的內容拷貝到數據目錄下便可。 二、增量備份測試 增量備份測試主要經過測試如下幾個場景,對數據備份和恢復進行驗證。 1)全庫備份,建立數據庫,增量備份,恢復測試 全庫備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup backup/ 建立數據庫 mysql -uroot -S/tmp/mysql.sock -e'create database backup_test_tmp;'mysql -uroot -S/tmp/mysql.sock -e'create table backup_test_tmp.test (id int);'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test_tmp.test values(1),(2),(3),(4),(5);' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復增量備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC> 恢復增量備份數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;'mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test_tmp.test;' 測試結果: 經驗證,備份恢復正確。 2)全庫備份,修改數據表結構,增量備份,恢復測試 全庫備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup backup/ 修改數據表結構 mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test add email varchar(20) default "null";' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/<DATE_TIME> 恢復增量備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC> 恢復增量備份數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,增量備份沒有問題。存在的不足是,恢復的時候,首先數據目錄必須爲空,其次,恢復的時候須要單獨拷貝增量備份的表結構。也就是說,在恢復階段,須要將數據目錄清空;數據恢復後,須要單獨拷貝增量備份文件夾下的表結構。 3)全庫備份,建立數據庫,增量備份,修改表結構,增量備份,恢復測試 全庫備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup backup/ 建立數據庫 mysql -uroot -S/tmp/mysql.sock -e'create database backup_test_tmp;'mysql -uroot -S/tmp/mysql.sock -e'create table backup_test_tmp.test (id int);'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test_tmp.test values(1),(2),(3),(4),(5);' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 修改數據表結構 mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test add email varchar(20) default "null";' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> 恢復增量備份1日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC1> 恢復增量備份2日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC2> 恢復增量備份數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經驗證,增量備份沒有問題。存在的不足是,恢復的時候,首先數據目錄必須爲空,其次,恢復的時候須要單獨拷貝最後一次增量備份的表結構。也就是說,在恢復階段,須要將數據目錄清空;數據恢復後,須要單獨拷貝最後一次增量備份文件夾下的表結構。 4)全備份某庫,修改庫,增量備份,恢復測試 全備份某庫 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test backup/ 修改庫 mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test add address varchar(20) default "null";' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/backup_test/* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --apply-log --user=backup backup/ <DATE_TIME> 恢復增量備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC> 恢復增量備份數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經 驗證,增量備份沒有問題。存在的不足是,恢復的時候,首先數據目錄必須爲空,其次,恢復的時候須要單獨拷貝增量備份的表結構。也就是說,在恢復階段,須要 將現有的數據目錄更名爲臨時目錄;在恢復以後,將原數據目錄(現臨時目錄)下的其餘庫的內容拷貝到數據目錄下便可。數據恢復後,還須要單獨拷貝增量備份文 件夾下的表結構。 5)innodb_file_per_table參數驗證 修改配置文件 在配置文件中添加innodb_file_per_table配置參數。 重啓數據庫server kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ')mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf & 建立測試庫backup_test mysql -uroot -S/tmp/mysql.sock -e'create database backup_test;'mysql -uroot -S/tmp/mysql.sock -e'create table backup_test.test (id int);'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test.test values(1),(2),(3),(4),(5);' 備份backup_test庫 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test --user=backup backup/ 修改庫 mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test add phone varchar(20) default "null";' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/backup_test/* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --apply-log --user=backup backup/ <DATE_TIME> 恢復增量備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC> 恢復增量備份數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test;' 測試結果: 經 驗證,增量備份沒有問題。存在的不足是,恢復的時候,首先數據目錄必須爲空,其次,恢復的時候須要單獨拷貝增量備份的表結構。也就是說,在恢復階段,須要 將現有的數據目錄更名爲臨時目錄;在恢復以後,將原數據目錄(現臨時目錄)下的其餘庫的內容拷貝到數據目錄下便可。數據恢復後,還須要單獨拷貝增量備份文 件夾下的表結構。 三、差分備份測試 差分備份實際是一次增量備份操做,該過程包含在增量備份測試中,再次再也不重複測試。 測試myisam 一、全備份測試 建立myisam數據表 mysql -uroot -S/tmp/mysql.sock -e'create table backup_test.test_myisam (id int) engine=myisam;'mysql -uroot -S/tmp/mysql.sock -e'insert into backup_test.test_myisam values(1),(2),(3),(4),(5);' 全備份數據表 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test.test_myisam backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/backup_test/test_myisam* 恢復日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test_myisam --apply-log --user=backup backup/ <DATE_TIME> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test_myisam --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test_myisam;' 測試結果: 經驗證,備份恢復正確。 二、增量備份測試 全備份數據表 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test.test_myisam backup/ 修改數據表結構 mysql -uroot -S/tmp/mysql.sock -e 'alter table backup_test.test_myisam add name varchar(20) default "null";' 增量備份 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --user=backup --database=backup_test.test_myisam --incremental --incremental-basedir=backup/<DATE_TIME> backup/ 關閉數據庫服務: kill -9 $(ps -ef|grep "mysql"|gawk '$0 !~/grep/ {print $2}' |tr -s '\n' ' ') 刪除當前數據文件: rm -rf /home/q/percona-server/data/backup_test/test_myisam* 恢復全備份日誌文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test_myisam --apply-log --user=backup backup/ <DATE_TIME> 恢復增量備份日誌文件 innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test_myisam --apply-log --user=backup backup/ <DATE_TIME> --incremental-dir=backup/<DATE_TIME_INC> 恢復數據文件: innobackupex --defaults-file=/home/q/percona-server/etc/my.cnf --database=backup_test.test_myisam --copy-back --user=backup backup/<DATE_TIME> 數據驗證: mysqld_safe --defaults-file=/home/q/percona-server/etc/my.cnf &mysql -uroot -S/tmp/mysql.sock -e'select * from backup_test.test_myisam;' 測試結果: 經驗證,備份恢復正確。 三、差分備份測試 差分備份實際是一次增量備份操做,該過程包含在增量備份測試中,再次再也不重複測試。 測試總結 設置以上場景,經測試,發現xtrabackup備份恢復工具仍然存在一些潛在的問題,可是這些問題徹底能夠經過規避或者完善腳本的方式,來改進和避免存在的問題。 實現原理 對於InnoDB,XtraBackup基於InnoDB的crash-recovery功能進行備份。 crash-recovery是這樣的:InnoDB維護了一個redo log,又稱爲 transaction log,也叫事務日誌,它包含了InnoDB數據的全部改動狀況。InnoDB啓動的時候先去檢查datafile和transaction log,而後應用全部已提交的事務並回滾全部未提交的事務。 XtraBackup在備份的時候並不鎖定表,而是一頁一頁地複製InnoDB的數據,與此同時,XtraBackup還有另一個線程監視着transactions log,一旦log發生變化,就把變化過的log pages複製走(由於transactions log文件大小有限,寫滿以後,就會從頭再開始寫,新數據可能會覆蓋到舊的數據,因此一旦變化就要馬上覆制走)。在所有數據文件複製完成以後,中止複製logfile。 XtraBackup採用了其內置的InnoDB庫以read-write模式打開InnoDB的數據文件,而後每次讀寫1MB(1MB/16KB=64page)的數據,一頁一頁地遍歷,同時用InnoDB的buf_page_is_corrupted()函數檢查此頁的數據是否正常,若是正常則進行復制,如不正常則從新讀取,最多重讀10次,若是仍是失敗,則備份失敗退出。複製transactions log的原理也是同樣的,只不過每次讀寫512KB(512KB/16KB=32page)的數據。 因爲XtraBackup其內置的InnoDB庫打開文件的時候是rw的,因此運行XtraBackup的用戶,必須對InnoDB的數據文件具備讀寫權限。 因爲XtraBackup要從文件系統中複製大量的數據,因此它儘量地使用posix_fadvise(),來告訴OS不要緩存讀取到的數據(由於這些數據不會重用到了),從而提高性能。若是要緩存的話,大量的數據會對OS的虛擬內存形成很大的壓力,其它進程(如mysqld)頗有可能會被swap出去,這樣就出問題了。同時,XtraBackup在讀取數據的時候還儘量地預讀。 因爲不鎖表,因此複製出來的數據是不一致的,數據的一致性是在恢復的時候使用crash-recovery進行實現的。 對於MyISAM,XtraBackup仍是首先鎖定全部的表,而後複製全部文件。 應用場景 基於以上原理,xtrabackup備份恢復工具比較適合數據增加型數據庫。對於數據增加型的庫,因爲數據的增加致使數據備份和恢復的空間和時間上的壓力較大。而xtrabackup有增量備份的功能,在短期內能夠經過進行增量備份來保證數據的安全性。而長期來看,仍然須要間斷性的進行全庫備份。此外,因爲xtrabackup對innodb的數據庫不進行鎖定,所以對要求不影響線上服務的數據備份和恢復較適合。 而對於數據量無明顯增加,且更新爲主的數據更新型數據庫,xtrabackup顯得過於複雜。xtrabackup操做反而不如mysqldump的性能高。 建議 經過以上測試,有如下建議,供DBA參考: 一、改進和完善innobackupex腳本,或者編寫備份恢復腳本。避免備份中存在的不足和可能出現的問題。 二、建議根據數據庫的類型,指定周密的備份恢復策略。