1. 程式人生 > >詳解mysql備份恢復的三種實現方式

詳解mysql備份恢復的三種實現方式

一、Mysql備份策略:

完整備份:

完整備份就是指對某一個時間點上的所有資料或應用進行的一個完整拷貝,對資料量大的,備份時間較長,當然資料在恢復的時候快。

增量備份:

備份自上一次備份(包括完整備份,差異備份,增量備份)之後所有變化的資料進行備份。恢復的時候只需要一次完整的備份加上完整備份後的多個增量備份進行恢復即可。

差異備份:

備份自上一次完整備份之後所有變化的資料,恢復的時候僅需要最新一次完整備份加上差異備份即可。

詳細如下圖所示:

備份方式:

1、使用 mysqldump 進行邏輯備份

2、使用 LVM 快照備份:

快照備份就是把當時的場景儲存為一個不變的狀態,然後對這個不變的狀態進行備份。但然,在規劃mysql資料庫時最好將資料和日誌分開放到lvm分割槽中。使用LVM快照備份,需要將資料放在lvm分割槽。

3、Xtrabackup備份:

備份原理:

       XtraBackup 基於 InnoDB  crash-recovery 功能。 它會複製 innodb data file ,由於不鎖表,複製出來的資料是不一致的, 在恢復的時候使用 crash-recovery ,使得資料恢復一致。 InnoDB 維護了一個 redo log ,又稱為 transaction log ,事務日誌, 它包含了 innodb 資料的所有改動情況。

當InnoDB啟動的時候,它會先去檢查datafile和transaction log,並且會做二步操作:

1.Itapplies committed transaction log entries to the data files

2.itperforms an undo operation on any transactions that modified data but did notcommit.

XtraBackup在備份的時候,一頁一頁地複製innodb的資料,而且不鎖定表,

與此同時,XtraBackup還有另外一個執行緒監視著transactionslog,

一旦log發生變化,就把變化過的logpages複製走。

為什麼要急著複製走呢?前幾章的時候就提過這個問題,

因為transactions log檔案大小有限,寫滿之後,就會從頭再開始寫,

所以新資料可能會覆蓋到舊的資料。

在prepare過程中,XtraBackup使用複製到的transactionslog 對備份出來的innodb data file 進行crash recovery。

用mysqldump實現備份:

首先,mysqldump是mysql的一個客戶端工具,可以實現備份整個伺服器、單個或部分資料庫、單個或部分表、表中的某些行,儲存過程,儲存函式,觸發器等,能自動記錄備份時的二進位制日誌檔案及相應的position值

二、詳解用mysqldump實現備份恢復操作:

首先,mysqldump是mysql的一個客戶端工具,可以實現備份整個伺服器、單個或部分資料庫、單個或部分表、表中的某些行,儲存過程,儲存函式,觸發器等,能自動記錄備份時的二進位制日誌檔案及相應的position值

對mysqldump引數說明:

--all-databases  , -A      // 匯出全部資料庫。

--all-tablespaces  , -Y     // 匯出全部表空間。

--no-tablespaces  , -y     // 不匯出任何表空間資訊。

--add-drop-database     // 每個資料庫建立之前新增drop資料庫語句。

--add-drop-table                 // 每個資料表建立之前新增drop資料表語句。(預設為開啟狀態,使用--skip-add-drop-table取消選項)

--add-locks                    // 在每個表匯出之前增加LOCK TABLES並且之後UNLOCK  TABLE。(預設為開啟狀態,使用--skip-add-locks取消選項)

--allow-keywords          // 允許建立是關鍵詞的列名字。這由表名字首於每個列名做到。

--apply-slave-statements // 在'CHANGE MASTER'前新增'STOP SLAVE',並且在匯出的最後新增'START SLAVE'。

--character-sets-dir        // 字符集檔案的目錄

--comments                   // 附加註釋資訊。預設為開啟,可以用--skip-comments取消

--compatible                  // 匯出的資料將和其它資料庫或舊版本的MySQL 相相容。值可以為ansi、mysql323、mysql40、postgresql、oracle、mssql、db2、maxdb、no_key_options、no_tables_options、no_field_options等,

要使用幾個值,用逗號將它們隔開。它並不保證能完全相容,而是儘量相容。

--compact                      // 匯出更少的輸出資訊(用於除錯)。去掉註釋和頭尾等結構。可以使用選項:--skip-add-drop-table  --skip-add-locks --skip-comments --skip-disable-keys

--complete-insert,  -c     // 使用完整的insert語句(包含列名稱)。這麼做能提高插入效率,但是可能會受到max_allowed_packet引數的影響而導致插入失敗。

--compress, -C      // 在客戶端和伺服器之間啟用壓縮傳遞所有資訊

--create-options,  -a      // 在CREATE TABLE語句中包括所有MySQL特性選項。(預設為開啟狀態)

--databases,  -B      // 匯出幾個資料庫。引數後面所有名字參量都被看作資料庫名。

--debug          // 輸出debug資訊,用於除錯。預設值為:d:t:o,/tmp/mysqldump.trace

--debug-check    // 檢查記憶體和開啟檔案使用說明並退出。

--debug-info       // 輸出除錯資訊並退出

--delete-master-logs           //master 備份後刪除日誌. 這個引數將自動啟用--master-data。

--disable-keys           // 對於每個表,用/*!40000 ALTER TABLE tbl_name DISABLE KEYS */;和/*!40000 ALTER TABLE tbl_name ENABLE KEYS */;語句引用INSERT語句。這樣可以更快地匯入dump出來的檔案,因為它是在插入所有行後建立索引的。該選項只適合MyISAM表,預設為開啟狀態。

--dump-slave // 該選項將導致主的binlog位置和檔名追加到匯出資料的檔案中。設定為1時,將會以CHANGE MASTER命令輸出到資料檔案;設定為2時,在命令前增加說明資訊。該選項將會開啟--lock-all-tables,除非--single-transaction被指定。該選項會自動關閉--lock-tables選項。預設值為0。

--events, -E      // 匯出事件。

--flush-logs   // 開始匯出之前重新整理日誌。

請注意:假如一次匯出多個數據庫(使用選項--databases或者--all-databases),將會逐個資料庫重新整理日誌。除使用--lock-all-tables或者--master-data外。在這種情況下,日誌將會被重新整理一次,相應的所以表同時被鎖定。因此,如果打算同時匯出和重新整理日誌應該使用--lock-all-tables 或者--master-data 和--flush-logs。

--flush-privileges // 在匯出mysql資料庫之後,發出一條FLUSH  PRIVILEGES 語句。為了正確恢復,該選項應該用於匯出mysql資料庫和依賴mysql資料庫資料的任何時候。

--ignore-table     // 不匯出指定表。指定忽略多個表時,需要重複多次,每次一個表。每個表必須同時指定資料庫和表名。

--lock-all-tables,  -x // 提交請求鎖定所有資料庫中的所有表,以保證資料的一致性。這是一個全域性讀鎖,並且自動關閉--single-transaction 和--lock-tables 選項。

mysqldump  -uroot -p --host=localhost --all-databases --lock-all-tables

--lock-tables,  -l      // 開始匯出前,鎖定所有表。用READ  LOCAL鎖定表以允許MyISAM表並行插入。對於支援事務的表例如InnoDB和BDB,--single-transaction是一個更好的選擇,因為它根本不需要鎖定表。

請注意當匯出多個數據庫時,--lock-tables分別為每個資料庫鎖定表。因此,該選項不能保證匯出檔案中的表在資料庫之間的邏輯一致性。不同資料庫表的匯出狀態可以完全不同。

--log-error     // 附加警告和錯誤資訊到給定檔案

--master-data // 該選項將binlog的位置和檔名追加到輸出檔案中。如果為1,將會輸出CHANGE MASTER 命令;如果為2,輸出的CHANGE  MASTER命令前添加註釋資訊。該選項將開啟--lock-all-tables 選項,除非--single-transaction也被指定(在這種情況下,全域性讀鎖在開始匯出時獲得很短的時間;其他內容參考下面的--single-transaction選項)。該選項自動關閉--lock-tables選項。

--no-create-db,  -n   // 只匯出資料,而不新增CREATE DATABASE 語句。

--no-create-info,  -t

只匯出資料,而不新增CREATE TABLE 語句。

mysqldump  -uroot -p --host=localhost --all-databases --no-create-info

--no-data, -d       // 不匯出任何資料,只匯出資料庫表結構。

--order-by-primary  // 如果存在主鍵,或者第一個唯一鍵,對每個表的記錄進行排序。在匯出MyISAM表到InnoDB表時有效,但會使得匯出工作花費很長時間。

--quick, -q     // 不緩衝查詢,直接匯出到標準輸出。預設為開啟狀態,使用--skip-quick取消該選項。

--opt         // 同時啟用各種高階選項

--routines, -R      // 匯出儲存過程以及自定義函式。

--single-transaction // 該選項在匯出資料之前提交一個BEGIN SQL語句,BEGIN 不會阻塞任何應用程式且能保證匯出時資料庫的一致性狀態。它只適用於多版本儲存引擎,僅InnoDB。本選項和--lock-tables 選項是互斥的,因為LOCK  TABLES 會使任何掛起的事務隱含提交。要想匯出大表的話,應結合使用--quick 選項。

--dump-date       // 將匯出時間新增到輸出檔案中。預設為開啟狀態,使用--skip-dump-date關閉選項。

--skip-opt           // 禁用–opt選項.

--socket,-S     // 指定連線mysql的socket檔案位置,預設路徑/tmp/mysql.sock

--triggers       // 匯出觸發器。該選項預設啟用,用--skip-triggers禁用它。

--user, -u        // 指定連線的使用者名稱。

--verbose, --v           // 輸出多種平臺資訊。

--version, -V        // 輸出mysqldump版本資訊並退出

例項詳解  操作時資料庫以及庫中的表可以自己建立,主要講解備份的過程及其中的要點

詳解一:對catidb資料庫進行完全備份:

mysql>use catidb;
Databasechanged
mysql>show tables;  //使用catidb資料庫檢視其中的表
+------------------+
|Tables_in_catidb |
+------------------+
|tb1              |
|tb2              |
+------------------+
2rows in set (0.00 sec)

對catidb資料庫進行備份,恢復

[[email protected]~]# mysqldump -uroot -pmypass catidb > /tmp/catidb.sql  //用這種方法對catidb資料庫進行備份,在資料庫恢復時有一個問題,即該catidb.sql檔案中沒用建立catidb資料庫的語句,在恢復時所含所有表會恢復到當前預設的資料庫中,相當的危險,因此需要謹慎,在恢復之前一定要先建立資料庫
mysql>drop database catidb;     //備份之後將catidb資料庫刪除
QueryOK, 2 rows affected (0.07 sec)
mysql>create database catidb;   //在恢復之前一定要先建立資料庫,資料庫名字可以自己定義
QueryOK, 1 row affected (0.04 sec)
mysql>use catidb;
Databasechanged
mysql>source /tmp/catidb.sql    //進行資料恢復
mysql>show tables;        //恢復成功
+------------------+
|Tables_in_catidb |
+------------------+
|tb1              |
|tb2              |
+------------------+
2rows in set (0.01 sec)

詳解二:

利用mysqldump實現從邏輯角度完全備份mysql,配合二進位制日誌備份實現增量備份

仍以上面的catidb資料庫為例先對catidb 資料庫進行完全備份

mysql>use catidb;
Databasechanged
mysql>show tables;
+------------------+
|Tables_in_catidb |
+------------------+
|tb1              |
|tb2              |
+------------------+
2rows in set (0.00 sec)

對catidb資料庫進行完全備份

[[email protected]~]# mysqldump -uroot -pmypass --single-transaction --master-data=2 --databasescatidb > /backup/catidb_`date +%F`.sql

備份完成之後又對catidb資料庫進行了新的操作

mysql>show tables;
+------------------+
|Tables_in_catidb |
+------------------+
|tb1              |
|tb2              |
+------------------+
2rows in set (0.00 sec)
mysql>use catidb
Databasechanged
mysql>create table tb3 (id int);
QueryOK, 0 rows affected (0.11 sec)
mysql>insert into tb3 values (1),(6),(9);
QueryOK, 3 rows affected (0.09 sec)
Records:3  Duplicates: 0  Warnings: 0

進行增量備份: 從上一次完全備份完成後,到所有新的操作之前,那麼如何檢視記錄的位置

開始位置:

[[email protected]~]# less /backup/catidb_2013-09-07.sql
--MySQL dump 10.13  Distrib 5.5.33, forLinux (x86_64)
--
--Host: localhost    Database: catidb
--------------------------------------------------------
--Server version       5.5.33-log
/*!40101SET @OLD[email protected]@CHARACTER_SET_CLIENT */;
/*!40101SET @OLD[email protected]@CHARACTER_SET_RESULTS */;
/*!40101SET @OLD[email protected]@COLLATION_CONNECTION */;
/*!40101SET NAMES utf8 */;
/*!40103SET @OLD[email protected]@TIME_ZONE */;
/*!40103SET TIME_ZONE='+00:00' */;
/*!40014SET @OLD[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014SET @OLD[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101SET @OLD[email protected]@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111SET @OLD[email protected]@SQL_NOTES, SQL_NOTES=0 */;
--
--Position to start replication or point-in-time recovery from
--
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=1673;

結束位置:

mysql>show master status;
+------------------+----------+--------------+------------------+
|File             | Position |Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000004 |     1959 |              |                  |
+------------------+----------+--------------+------------------+
1row in set (0.00 sec)

二進位制增量備份

[[email protected]~]# mysqlbinlog --start-position=1673 --stop-position=1959/mydata/data/mysql-bin.000004 > /backup/catidb_`date +%F_%H`.sql

之後又進行了一些操作

記錄一次此刻二進位制日誌的位置

mysql>show master status;
+------------------+----------+--------------+------------------+
|File             | Position |Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
|mysql-bin.000004 |     1959 |              |                  |
+------------------+----------+--------------+------------------+
1row in set (0.00 sec)
mysql>use catidb;
Databasechanged
mysql>insert into tb3 values (2),(5);
QueryOK, 2 rows affected (0.11 sec)
Records:2  Duplicates: 0  Warnings: 0

之後不小心刪除了catidb資料庫

mysql>drop database catidb;

QueryOK, 3 rows affected (0.13 sec)

開始進行恢復操作,首先把所需二進位制日誌匯出來

[root@localhost~]# mysqlbinlog --start-position=1959 /mydata/data/mysql-bin.000004
/*!50530SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019SET @@session.max_insert_delayed_threads=0*/;
/*!50003SET @[email protected]@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER/*!*/;
#at 4
#130907  5:41:54 server id 1  end_log_pos 107      Start: binlog v 4, server v 5.5.33-log created 130907  5:41:54 at startup
#Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
BINLOG'
IkwqUg8BAAAAZwAAAGsAAAABAAQANS41LjMzLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAiTCpSEzgNAAgAEgAEBAQEEgAAVAAEGggAAAAICAgCAA==
'/*!*/;
#at 1959
#130907  9:53:14 server id 1  end_log_pos 2029    Query  thread_id=6    exec_time=0 error_code=0
SETTIMESTAMP=1378518794/*!*/;
SET@@session.pseudo_thread_id=6/*!*/;
SET@@session.foreign_key_checks=1, @@session.sql_auto_is_null=0,@@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET@@session.sql_mode=0/*!*/;
SET@@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\Cutf8 *//*!*/;
SET@@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET@@session.lc_time_names=0/*!*/;
SET@@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
#at 2029
#130907  9:53:14 server id 1  end_log_pos 2124    Query  thread_id=6    exec_time=0 error_code=0
use`catidb`/*!*/;
SETTIMESTAMP=1378518794/*!*/;
insertinto tb3 values (2),(5)
/*!*/;
#at 2124
#130907  9:53:14 server id 1  end_log_pos 2151    Xid = 175
COMMIT/*!*/;
# at 2151
#130907  9:54:04 server id 1  end_log_pos 2236    Query  thread_id=6    exec_time=1 error_code=0
SETTIMESTAMP=1378518844/*!*/;
drop database catidb
/*!*/;
DELIMITER;
#End of log file
ROLLBACK/* added by mysqlbinlog */;
/*!50003SET [email protected]_COMPLETION_TYPE*/;
/*!50530SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

注意我們儲存的是drop catidb資料庫之前的內容,因此需要檢視其中的位置,此時為2151

開始匯出二進位制日誌

[[email protected]~]# mysqlbinlog --start-position=1959 --stop-position=2151/mydata/data/mysql-bin.000004 > /tmp/catidb_binlog.sql

開始恢復,此時不需要啟動二進位制日誌

mysql>set sql_log_bin=0;
QueryOK, 0 rows affected (0.00 sec)
mysql>flush logs; //滾動二進位制日誌
QueryOK, 0 rows affected (0.17 sec)

可以在命令列中進行匯入,進行恢復操作,完全備份+增量備份+二進位制日誌

[root@localhost~]# mysql -uroot -pmypass < /backup/catidb_2013-09-07.sql //恢復完全備份
[root@localhost~]# mysql -uroot -pmypass < /backup/catidb_2013-09-07_09.sql     //恢復增量備份
[root@localhost~]# mysql -uroot -pmypass < /tmp/catidb_binlog.sql      //恢復二進位制日誌

之後連到Mysql,進行檢視

mysql>use catidb;
Databasechanged
mysql>show tables;
+------------------+
|Tables_in_catidb |
+------------------+
|tb1              |
|tb2              |
|tb3              |
+------------------+
3rows in set (0.00 sec)
mysql>select * from tb3;
+------+
|id   |
+------+
|    1 |
|    6 |
|    9 |
|    2 |
|    5 |
+------+
5rows in set (0.00 sec)

備份恢復完成!

注意:對於一般的備份,是針對整個伺服器進行備份的因此所用的選項應該是—all-databases;

三、詳解利用lvm的快照來備份Mysql及其恢復

首先進行一次完全備份

[root@localhost~]# mysqldump -uroot -pmypass --lock-all-tables --all-databases --events >/backup/all_db_`date +%F`.sql
[root@localhost~]# service mysqld stop 停止Mysql服務
Shuttingdown MySQL....                                    [  OK  ]
[root@localhost~]# rm -rf /mydata/*

要求建立邏輯卷並將其掛載至/mydata下,過程不在演示

[root@localhost~]# mount
/dev/mapper/vg0-rooton / type ext4 (rw)
procon /proc type proc (rw)
sysfson /sys type sysfs (rw)
devptson /dev/pts type devpts (rw,gid=5,mode=620)
tmpfson /dev/shm type tmpfs (rw)
/dev/sda1on /boot type ext4 (rw)
/dev/mapper/vg0-usron /usr type ext4 (rw)
/dev/mapper/vg0-varon /var type ext4 (rw)
noneon /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
sunrpcon /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
/dev/mapper/myvg-mydata on /mydata type ext4 (rw)
[root@localhost~]# mkdir /mydata/data/ 在邏輯捲上建立資料目錄
[root@localhost~]# chown -R mysql.mysql /mydata/data修改資料目錄的許可權
[root@localhost~]# cd /usr/local/mysql
[root@localhostmysql]# scripts/mysql_install_db --user=mysql --datadir=/mydata/data  //初始化指令碼

在配置檔案中新增/etc/my.cnf

[mysqld]
port            = 3306
socket          = /tmp/mysql.sock
skip-external-locking
key_buffer_size= 256M
max_allowed_packet= 1M
table_open_cache= 256
sort_buffer_size= 1M
read_buffer_size= 1M
read_rnd_buffer_size= 4M
myisam_sort_buffer_size= 64M
thread_cache_size= 8
query_cache_size=16M
#Try number of CPU's*2 for thread_concurrency
thread_concurrency= 8
datadir=/mydata/data
sync_binlog= 1

啟動mysqld服務

[[email protected]~]# service mysqld start

連到Mysql上

mysql>set session sql_log_bin=0; 關閉二進位制日誌
QueryOK, 0 rows affected (0.00 sec)
mysql>source /backup/all_db_2013-09-07.sql 恢復所有資料庫
mysql>show databases;
+--------------------+
|Database           |
+--------------------+
|information_schema |
|catidb             |
|hailian            |
|hellodb            |
|mysql              |
|performance_schema |
|test               |
+--------------------+
7rows in set (0.00 sec)
mysql>\q
Bye

從新連到Mysql是為了開啟二進位制日誌功能

mysql>show binary logs;
+------------------+-----------+
|Log_name         | File_size |
+------------------+-----------+
|mysql-bin.000001 |     27719 |
|mysql-bin.000002 |   1061358 |
|mysql-bin.000003 |       182 |
+------------------+-----------+
3rows in set (0.00 sec)
mysql>flush tables with read lock;
QueryOK, 0 rows affected (0.09 sec)
mysql>show master status;
+------------------+----------+--------------+------------------+
|File             | Position |Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
|mysql-bin.000003 |      182 |              |                  |
+------------------+----------+--------------+------------------+
1row in set (0.00 sec)
也可以通過[[email protected] ~]# mysql -uroot -pmypass -e 'show master status'> /backup/snapback-2
013-09-07/binlog.txt儲存到binlog.txt文件中
[[email protected]~]# lvcreate -L 100M -n mydata-snap -p r -s /dev/myvg/mydata
mysql>unlock tables;
QueryOK, 0 rows affected (0.00 sec)
[[email protected]~]# cp -a /mydata/data/* /backup/snapback-2013-09-07/

之後連到mysql上有進行了一下操作

mysql>use hellodb;
Databasechanged
mysql>show tables;
+-------------------+
|Tables_in_hellodb |
+-------------------+
|classes           |
|coc               |
|courses           |
|scores            |
|students          |
|teachers          |
|toc               |
+-------------------+
7rows in set (0.00 sec)
mysql>create table testtb (id int, name char(10));
QueryOK, 0 rows affected (0.12 sec)
mysql>insert into testtb values (1,'tom');
QueryOK, 1 row affected (0.10 sec)
[[email protected]~]# mysqlbinlog --start-position=187 /mydata/data/mysql-bin.000003 >/backup/snapback-2013-09-07_incremental/incremental.sql
[[email protected]~]# service mysqld stop
[[email protected]~]# rm -rf /myda