MySQL熱備份工具innobackupex介紹及應用 ------ 經常使用備份方式

  innobackupex是一個perl腳本對xtrbackup的封裝,支持InnoDB/XtraDB表數據在線熱備份和相關數據結構,對於MyISAM表的備份會產生表鎖。html

鏈接到數據庫
mysql

innobackupex --user=DBUSER --password=SECRET /path/to/backup/dir
innobackupex --user=LUKE --password=US3TH3F0RC3 --stream=tar ./ | bzip2 -
xtrabackup --user=DVADER --password=14MY0URF4TH3R --backup --target-dir=/data/bkps/

其餘選項sql

--port   數據庫端口
--socket 套接字地址
--host   主機地址


備份方式:shell

全量備份 - 原理 數據庫

對於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)的數據。
app

因爲XtraBackup其內置的InnoDB庫打開文件的時候是rw的,因此運行XtraBackup的用戶,必須對InnoDB的數據文件具備讀寫權限。
socket

因爲XtraBackup要從文件系統中複製大量的數據,因此它儘量地使用posix_fadvise(),來告訴OS不要緩存讀取到的數據(由於這些數據不會重用到了),從而提高性能。若是要緩存的話,大量的數據會對OS的虛擬內存形成很大的壓力,其它進程(如mysqld)頗有可能會被swap出去,這樣就出問題了。同時,XtraBackup在讀取數據的時候還儘量地預讀。

因爲不鎖表,因此複製出來的數據是不一致的,數據的一致性是在恢復的時候使用crash-recovery進行實現的。

對於MyISAM,XtraBackup仍是首先鎖定全部的表,而後複製全部文件。

全量備份 - 方式

innobackupex --user=DBUSER  --password=SECRET  --host=localhost --port=3306 --defaults-file=/etc/my.cnf --tmpdir=/tmp --slave-info --stream=tar /path/to/backup/dir 2 > full-bak.log  | gzip 1> full-bak.tar.gz

參數說明:

--defaults-file=[my.cnf]    同xtrabackup的--defaults-file參數,innobackupex選項文件,主要指定InnoDB相關參數信息,直接指定my.cnf
--slave-info                備份從庫, 加上--slave-info備份目錄下會多生成一個xtrabackup_slave_info 文件,這裏會保存主日誌文件以及偏移, 文件內容相似於:CHANGE MASTER TO MASTER_LOG_FILE='', MASTER_LOG_POS=0
--stream=[tar]              備份文件輸出格式, tar時使用tar4ibd , 該文件可在XtarBackup binary文件中得到.若是備份時有指定--stream=tar, 則tar4ibd文件所處目錄必定要在$PATH中(由於使用的是tar4ibd去壓縮, 在XtraBackup的binary包中可得到該文件)。 
--tmpdir                    在使用參數stream=tar備份的時候,你的xtrabackup_logfile可能會臨時放在/tmp目錄下,若是你備份的時候併發寫入較大的話xtrabackup_logfile可能會很大(5G+),極可能會撐滿你的/tmp目錄,能夠經過參數--tmpdir指定目錄來解決這個問題。

增量備份 - 原理

在完整備份和增量備份文件中都有一個文件xtrabackup_checkpoints會記錄備份完成時檢查點的LSN。在進行新的增量備份時,XtraBackup會比較表空間中每頁的LSN是否大於上次備份完成的LSN,若是是,則備份該頁,並記錄當前檢查點的LSN。

增量備份 - 方式

innobackupex --user=DBUSER  --password=SECRET  --host=localhost --port=3306 --defaults-file=/etc/my.cnf --tmpdir=/tmp --slave-info --stream=xbstream --compress --incremental /path/to/backup/incr-dir --incremental-basedir /path/to/backup/dir 2 > incr-bak.log  | gzip 1> incr-bak.tar.gz

參數說明:

--incremental                 增量備份目錄
--incremental-basedir         前一次備份目錄
--incremental-lsn=LSN-number  前一次備份的LSN值,只備份比這個值新的ibd pages
--compress                    壓縮備份此選項不兼容--stream=tar,只兼容--stream=xbstream,此外加密項encrypted也不能兼容--stream=tar

單庫備份

默認參數中--databases=LIST能夠備份單庫,這個參數說明雖然是指定須要備份數據庫,但實際運行過程當中它會備份系統中全部數據庫的InnoDB表。實際中若是要對單個數據庫進行備份可使用--include=REGEXP,如備份test庫能夠--include='test.*'備份test庫下全部數據表


備份恢復:

全備恢復

innobackupex --apply-log --use-memory=4G /path/to/BACKUP-DIR
/etc/init.d/mysqld stop
innobackupex --copy-back /path/to/BACKUP-DIR
chown -R mysql:mysql /var/lib/mysql
/etc/init.d/mysqld start

參數說明:

--apply-log        在數據庫備份好後,這些備份的數據並不能當即用於恢復,由於這些剛備份的數據裏包含了未提交的數據,須要回滾undo數據!也包括的已完成的事務在重作日誌文件中並無寫入數據文件中,這些數據須要重作redo  這個參數正是用於作這些事情,以保證數據文件的一致性。在數據庫恢復以前,須先對備份的數據文件應用此參數。(innobackup會重現重作日誌文件(redo log file)中的事務條目,重作已經提交的事務和回滾未提交的事務
--use-memory=4G    此參數用來控制備份所使用到的內存大小,默認爲100M! 通常與--apply-log一塊兒使用
--copy-back        把備份數據拷貝回server的datadir,它決定於my.cnf中的datadir參數,另外在恢復時datadir目錄必須是空的,而且mysql數據庫必須爲關閉狀態


增量恢復

innobackupex --apply-log --redo-only /path/to/BACKUP-DIR    # 全備目錄
innobackupex --apply-log --redo-only /path/to/BACKUP-DIR --incremental-dir=/path/to/INCREMENTAL-DIR-1    # 第一次增備目錄
innobackupex --apply-log /path/to/BACKUP-DIR --incremental-dir=/path/to/INCREMENTAL-DIR-2    # 第二次增備目錄
innobackupex --apply-log /path/to/BACKUP-DIR
/etc/init.d/mysqld stop
innobackupex --copy-back /path/to/BACKUP-DIR
chown -R mysql:mysql /var/lib/mysql
/etc/init.d/mysqld start

參數說明:

--redo-only    在作增量恢復時,全備和增量備份的數據文件在恢復前必須先將在重作日誌文件中的已提交的事務重作。此參數將會合並全備和增量備份的數據文件,但不包括最後一次增量備份的數據文件


單表恢復

innobackupex --apply-log --export /path/to/backup
CREATE TABLE mytable (...) ENGINE=InnoDB;
ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
cp /path/to/backup/mydatabase/mytables.ibd /var/lib/mysql/mydatabase/
cp /path/to/backup/mydatabase/mytable.exp /var/lib/mysql/mydatabase/
cp /path/to/backup/mydatabase/mytable.cfg /var/lib/mysql/mydatabase/
chown mysql.mysql -R /var/lib/mysql/mydatabase
ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;

參數說明:

--export    導出單個表

使用限制:

由於針對單個表恢復生成的數據文件爲單個表空間數據文件,因此數據庫必須使用innodb_file_per_table來爲每一個表使用獨立表空間

以上方法在MySQL 5.6或Percona Server 5.6中能夠成功倒入表空間數據,在MySQL 5.6以前的版本須要其餘額外的操做才能完成數據恢復。

ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;

MySQL 5.6以前的版本上面的語句會產生

root@localhost [innodb_test] 04:58:15>ALTER TABLE innodb1 IMPORT TABLESPACE;
ERROR 1030 (HY000): Got error -1 from storage engine
root@localhost [innodb_test] 04:59:03>

日誌中爲:

141022 16:59:03  InnoDB: Error: tablespace id and flags in file './innodb_test/innodb1.ibd' are 815 and 0, but in the InnoDB
InnoDB: data dictionary they are 819 and 0.
InnoDB: Have you moved InnoDB .ibd files around without using the
InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?
InnoDB: Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/innodb-troubleshooting-datadict.html
InnoDB: for how to resolve the issue.
141022 16:59:03  InnoDB: cannot find or open in the database directory the .ibd file of
InnoDB: table `innodb_test`.`innodb1`
InnoDB: in ALTER TABLE ... IMPORT TABLESPACE

這是由於新表的tablespace id和原來的tablespace id不一致致使不能成功倒入表空間。解決的辦法是咱們新建立一個數據庫實例不斷的建立和刪除表當表的tablespace id與老的tablespace id一直時咱們將表空間的數據倒入到新表而後使用mysqldump對數據進行備份而後倒入的原來的數據庫中。

  示例中tablespace id爲815咱們須要再建立813個 innodb table,(table id 1已經被佔用,須要比對應.ibd 文件的table id 小1, 因此是 815-2=813 )

drop procedure if exists proc_createtable;
delimiter &&

create procedure proc_createtable()
begin

declare tid int;

set tid=0; 
repeat
  set tid=tid+1;
  create table t (id int);
  drop table t;
  insert into innodb1 values (tid);
until tid=813 end repeat;

end&&

delimiter ;

複製表空間數據

ALTER TABLE mydatabase.mytable DISCARD TABLESPACE;
cp /path/to/backup/mydatabase/mytables.ibd /var/lib/mysql/mydatabase/
cp /path/to/backup/mydatabase/mytable.exp /var/lib/mysql/mydatabase/
cp /path/to/backup/mydatabase/mytable.cfg /var/lib/mysql/mydatabase/
chown mysql.mysql -R /var/lib/mysql/mydatabase
ALTER TABLE mydatabase.mytable IMPORT TABLESPACE;

備份表數據

mysqldump -uroot -proot -P 3322 innodb_test innodb1 > innodb1.sql

恢復表數據

mysqldump -uroot -proot innodb_test < innodb1.sql
相關文章
相關標籤/搜索