MySQL數據庫備份分爲邏輯備份和物理備份兩大類,猶豫到底用那種備份方式的時候先了解下它們的差別:html
邏輯備份的特色是:直接生成SQL語句,在恢復的時候執行備份的SQL語句實現數據庫數據的重現。
物理備份的特色是:拷貝相關數據文件。
這二種備份差別 :邏輯備份其備份、還原慢,但備份文件佔用的空間小;物理備份其備份還原快,備份文件佔用空間大。
到底選擇那種備份方式,具體根據本身的實際狀況,如須要的是熱備仍是冷備?數據量大不大?磁盤空間夠不夠等因素決定。mysql
邏輯備份工具主要有:mysqldump、mysqlpump、mydumper,物理備份工具主要有:xtrabackup。sql
如今使用最多的備份就是mysqldump、xtrabackup(都支持支持熱備),本文就mysqldump(mysqlpump)和xtrabackup的原理進行下大體的說明。數據庫
1)參數說明,具體的參數能夠用mysqldump --help查看。服務器
在說明mysqldump以前先了解下它的相關參數,能夠經過mysqldump --help進行查看,也能夠經過mysqldump、mysqlpump備份工具說明和mysqldump的流程進行了解。這裏再重申一下幾個比較重要的參數。
session
經過將導出操做封裝在一個事務(Repeatable Read)內來使得導出的數據是一個一致性快照。只有當表使用支持MVCC的存儲引擎(目前只有InnoDB)時才能夠工做;其餘引擎不能保證導出是一致的。當導出開啓了–single-transaction選項時,要確保導出文件有效(正確的表數據和二進制日誌位置),就要保證沒有其餘鏈接會執行以下語句:ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,這會致使一致性快照失效。這個選項開啓後會自動關閉lock-tables。而且在mysql5.7.11以前,--default-parallelism大於1的時候和此參也互斥,必須使用--default-parallelism=0。5.7.11以後解決了--single-transaction和--default-parallelism的互斥問題。
②:--master-data函數
這個選項能夠把binlog的位置和文件名添加到輸出中,若是等於1,將會打印成一個CHANGE MASTER命令;若是等於2,會加上註釋前綴。而且這個選項會自動打開–lock-all-tables,除非同時設置了–single-transaction(這種狀況下,全局讀鎖只會在開始dump的時候加上一小段時間,不要忘了閱讀–single-transaction的部分)。在任何狀況下,全部日誌中的操做都會發生在導出的準確時刻。這個選項會自動關閉–lock-tables。打開該參數須要有reload權限,而且服務器開啓binlog。
③:--lock-all-tables ,-x工具
鎖定全部庫中全部的表。這是經過在整個dump的過程當中持有全局讀鎖來實現的。會自動關閉–single-transaction 和 –lock-tables。
④:--lock-tables,
-l
post
備份某個庫就鎖該庫的全部表,用READ LOCAL來鎖表。MyISAM容許併發寫入,由於鎖表只針對指定的數據庫,不能保證物理上的一致性,不一樣庫的表備份完成時會有不一樣的狀態。用–skip-lock-tables來關閉。
⑤:--flush-logs,
-F
在開始導出前刷新服務器的日誌文件。注意,若是你一次性導出不少數據庫(使用--databases= 或--all-databases 選項),導出每一個庫時都會觸發日誌刷新。例外是當使用了--lock-all-tables、--master-data或--single-transaction時:日誌只會被刷新一次,那個時候全部表都會被鎖住。因此若是你但願你的導出和日誌刷新發生在同一個肯定的時刻,你須要使用--lock-all-tables、--master-data和--single-transaction配合 –flush-logs。
⑥:--opt
該參數默認開啓,表示快遞啓動--add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset選項,經過 --skip-opt 關閉。
2)執行說明
①:邏輯備份就是導出SQL形式的文件,其的具體實現步驟能夠直接打開genaral_log。
general_log_file = /var/log/mysql/mysql.log general_log = 1
②:備份須要保證數據庫的一致性,即在某一時刻,整個數據庫的狀態是一致的,這樣能夠經過備份進行恢復成爲另外一個從庫。數據庫目前使用最多的存儲引擎是InnoDB,也有可能部分是MyISAM,建議把MyISAM存儲引發改爲InnoDB。如今重點說明關於InnoDB的備份。
MyISAM表的備份選項:上面提過由於mysqldump默認開啓--opt選項,而--opt裏包含--lock-tables的選項,這個選項不能保證在多個數據庫下數據備份的一致性,因此要麼--skip-opt,再把須要的選項添加進去,要麼就再使用--lock-all-tables的選項(開啓以後會關閉--lock-tables的選項),要是在從庫備份則只須要添加--master-data選項(開啓以後自動打開--lock-all-tables選項)便可。
備份myisam表的命令:
mysqldump -uroot -p123 --default-character-set=utf8 --master-data=1 -R -E --triggers -B dba_test dba_test2 > /home/dxy/dba_test.sql
由於開啓了--lock-all-tables選項(--master-data),保證一致性讀和數據的一致性。在備份開始時就會執行FLUSH TABLES WITH READ LOCK命令,這個命令是server層面的鎖,這樣後面任何存儲引擎執行DML、DDL語句都會 Waiting for global read lock狀態,這樣就保證了從備份點以後數據的一致性。
InnoDB表的備份選項:和上面介紹MyISAM表的備份選項同樣,在此基礎上增長了--single-transaction的選項,這個選項保證了經過將導出操做封裝在一個事務(Repeatable Read)內來使得導出的數據是一個一致性快照。只有當表使用支持MVCC的存儲引擎(目前只有InnoDB)時才能夠工做,其餘引擎不能保證導出是一致的。這個選項開啓後會自動關閉--lock-tables選項,而--master-data選項自動打開–lock-all-tables選項,在設置了--single-transaction這種狀況下,全局讀鎖只會在開始dump的時候加上一小段時間(5.7以前),5.7以後不須要加鎖了。
一致性快照,即一致性讀取,那是如何保證一致性讀的呢?具體的說明能夠看MySQL 一致性讀 深刻研究這篇文章。大體的說明能夠看下面的測試說明:
測試1:
sesseion A | session B |
mysql> set tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)
|
mysql> set tx_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)
|
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
|
|
mysql> select * from t1;
Empty set (0.00 sec)
mysql> insert into t1(c1,c2) values(1,1);
Query OK, 1 row affected (0.01 sec)
|
|
mysql> select * from t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | 1 |
+----+------+
1 row in set (0.00 sec)
|
結論1:RR隔離級別下的一致性讀,不是以begin開始的時間點做爲snapshot創建時間點,由於測試看出再begin一個事務的時候,表是沒有數據的,sessionB寫入數據以後,卻能看到數據。
測試2:
session A | session B |
mysql> set tx_isolation='repeatable-read'; | mysql> set tx_isolation='repeatable-read'; |
mysql> select * from t1;
Empty set (0.00 sec)
|
|
mysql> begin;
mysql> select * from t;
|
|
mysql> insert into t1(c1,c2) values(1,1);
Query OK, 1 row affected (0.01 sec)
|
|
mysql> select * from t1;
Empty set (0.00 sec) |
結論2:RR隔離級別下的一致性讀,是以第一條select語句的執行點做爲snapshot創建的時間點的,即便是不一樣表的select語句。這裏由於session A在insert以前對 t 表執行了select,因此創建了snapshot,因此後面的select * from t1 不能讀取到insert的插入的值(snapshot的時候t1表沒有數據)。
測試3:
session A | session B |
mysql> set tx_isolation='repeatable-read'; |
mysql> set tx_isolation='repeatable-read';
mysql> select * from t1;
Empty set (0.00 sec)
|
mysql> begin; | |
mysql> select * from t1;
Empty set (0.00 sec)
|
mysql> select * from t1;
Empty set (0.00 sec)
|
mysql> insert into t1(c1,c2) values(1,1); | |
mysql> select * from t1;
Empty set (0.01 sec)
|
結論3:session A 的第一條語句,發生在session B的 insert語句提交以前,因此session A中的第二條select仍是不能讀取到數據。由於RR中的一致性讀是以事務中第一個select語句執行的時間點做爲snapshot創建的時間點的。而此時,session B的insert語句尚未執行,因此讀取不到數據。
測試4:
session A | session B |
mysql> set tx_isolation='repeatable-read'; |
mysql> set tx_isolation='repeatable-read';
mysql> select * from t1;
Empty set (0.00 sec)
|
mysql> select * from t1;
Empty set (0.00 sec)
|
|
mysql> insert into t1(c1,c2) values(1,1),(2,2);
mysql> select * from t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | 1 |
| 2 | 2 |
+----+------+
2 rows in set (0.01 sec)
|
|
mysql> select * from t1;
Empty set (0.00 sec)
|
|
mysql> update t1 set c2=100 where c1=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | 100 |
+----+------+
1 row in set (0.00 sec)
|
結論4:本事務中進行修改的數據,即便沒有提交,在本事務中的後面也能夠讀取到。update 語句由於進行的是「當前讀」,因此它能夠修改爲功。
經過上面的幾個測試得出的結論:對同一個表或者不一樣表進行的第一次select語句創建了該事務中一致性讀的snapshot,在snapshot創建以後提交的數據,一致性讀就讀不到,以前提交的數據就能夠讀到。事務一致性讀的起始點實際上是以執行的第一條語句爲起始點的,而不是以begin做爲事務的起始點的。
通常begin/start transaction是開始一個事務的標誌,但不是事務開始的時間點,也就是說執行了start transaction以後的第一個語句(任何語句),事務才真正的開始。可是若是要達到將 start transaction做爲事務開始的時間點,那麼必須使用:
START TRANSACTION WITH consistent snapshot ###mysqldump中的快照就是用這個實現的
這樣開啓事務效果等價於: start transaction 以後,立刻執行一條 select 語句(此時會創建一致性讀的snapshot)。
測試5:
session A | session B |
mysql> set tx_isolation='repeatable-read'; | mysql> set tx_isolation='repeatable-read'; |
mysql> select * from t1;
Empty set (0.01 sec)
|
|
mysql> start transaction; | |
mysql> insert into t1(c1,c2) values(1,1); | |
mysql> select * from t1;
+----+------+
| c1 | c2 |
+----+------+
| 1 | 1 |
+----+------+
1 row in set (0.00 sec)
|
mysql> set tx_isolation='repeatable-read'; | mysql> set tx_isolation='repeatable-read'; |
mysql> select * from t1;
Empty set (0.01 sec)
|
|
mysql> start transaction with consistent snapshot; | |
mysql> insert into t1(c1,c2) values(1,1); | |
mysql> select * from t1;
Empty set (0.00 sec)
|
因此事務一致性快照開始時間點,分爲兩種狀況:
1)START TRANSACTION時,第一條語句的執行時間點,就是事務開始的時間點,第一條select語句創建一致性讀的snapshot; 2)START TRANSACTION WITH consistent snapshot時,則是當即創建本事務的一致性讀snapshot,固然也開始事務了;
到此,大體說明了參數single-transaction的意義,其實就是經過start transaction with consistent snapshot實現一致性快照讀:經過將導出操做封裝在一個事務內來使得導出的數據是一個一致性快照。只有當表使用支持MVCC的存儲引擎(目前只有InnoDB)時才能夠工做,其餘引擎(MyISAM)不能保證導出是一致的。如備份開啓以後,經過一致性快照記錄了mysql的binlog和position,此時往innodb表裏寫入數據,由於有一致性快照,備份讀不到最新的記錄,可是該操做會在以前記錄binlog以後位置裏記錄,當還原的時候,直接應用以後的binlog記錄便可。而myisam不支持事務,沒有快照,備份直接取最新數據,而寫入操做會持續記錄到binlog裏,因此還原的時候會致使一致性被破環。當還原到一個新從並開啓同步的change(備份裏面記錄的點)以後,myisam表會出現主鍵衝突,而innodb表不會。
備份InnoDB表的命令:
mysqldump -uroot -p123 --default-character-set=utf8 --single-transaction --master-data=1 -R -E --triggers -B dba_test dba_test2 > /home/dxy/dba_test.sql
上面講了這麼多,如今經過general_log看看mysqlbinlog備份步驟:
2016-08-21T00:08:11.755486+08:00 15 Connect root@localhost on using Socket ##備份的鏈接方式 2016-08-21T00:08:11.793153+08:00 15 Query /*!40100 SET @@SQL_MODE='' */ ##備份的SQL_MODE 2016-08-21T00:08:11.815880+08:00 15 Query /*!40103 SET TIME_ZONE='+00:00' */ ##備份的時區,--tz-utc,用--skip-tz-utc關閉 ##2016-08-21T00:08:11.815880+08:00 15 Query FLUSH /*!40101 LOCAL */ TABLES ##刷新表,5.6以前有,5.7沒有 ##2016-08-21T00:08:11.815880+08:00 15 Query FLUSH TABLES WITH READ LOCK ##加全局讀鎖,--lock-all-tables的做用。5.6以前有,5.7沒有。5.7的mysqldump加了--single-transaction不須要鎖表了? 2016-08-21T00:08:11.815981+08:00 15 Query SHOW STATUS LIKE 'binlog_snapshot_%' ##binlog的文件名和偏移量,--master-data的做用,5.6以前是用SHOW MASTER STATUS表示 2016-08-21T00:08:11.822342+08:00 15 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ##--single-transaction的做用,設置成RR級別 2016-08-21T00:08:11.822457+08:00 15 Query START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */ ##--single-transaction的做用,設置成一致性快照讀 2016-08-21T00:08:11.822675+08:00 15 Query SHOW VARIABLES LIKE 'gtid\_mode' 2016-08-21T00:08:11.868728+08:00 15 Query SHOW STATUS LIKE 'binlog_snapshot_%' ##binlog的文件名和偏移量,--master-data的做用,5.6以前是用SHOW MASTER STATUS表示 2016-08-21T00:08:11.868940+08:00 15 Query UNLOCK TABLES ##解鎖表,印證了全局讀鎖只會在開始dump的時候加上一小段時間(5.7以前),5.7以後不須要加鎖了
#上面黃色背景表示備份前的一些準備工做:一致性快照、鎖、二進制日誌等信息。
2016-08-21T00:08:11.900984+08:00 15 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA IN ('dba_test','dba_test2'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE, EXTRA ORDER BY LOGFILE_GROUP_NAME 2016-08-21T00:08:12.000013+08:00 15 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA IN ('dba_test','dba_test2')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME 2016-08-21T00:08:12.000954+08:00 15 Query SHOW VARIABLES LIKE 'ndbinfo\_version' 2016-08-21T00:08:12.001309+08:00 15 Init DB dba_test 2016-08-21T00:08:12.001387+08:00 15 Query SHOW CREATE DATABASE IF NOT EXISTS `dba_test` 2016-08-21T00:08:12.001505+08:00 15 Query SAVEPOINT sp ##--single-transaction的做用 2016-08-21T00:08:12.001564+08:00 15 Query show tables 2016-08-21T00:08:12.001645+08:00 15 Query show table status like 'abc' 2016-08-21T00:08:12.001747+08:00 15 Query SET SQL_QUOTE_SHOW_CREATE=1 2016-08-21T00:08:12.001772+08:00 15 Query SET SESSION character_set_results = 'binary' 2016-08-21T00:08:12.001799+08:00 15 Query show create table `abc` 2016-08-21T00:08:12.001835+08:00 15 Query SET SESSION character_set_results = 'utf8' 2016-08-21T00:08:12.001864+08:00 15 Query show fields from `abc` 2016-08-21T00:08:12.002013+08:00 15 Query show fields from `abc` 2016-08-21T00:08:12.002150+08:00 15 Query SELECT /*!40001 SQL_NO_CACHE */ * FROM `abc` ##表示備份表的語句 2016-08-21T00:08:12.021228+08:00 15 Query SET SESSION character_set_results = 'binary'
#上面藍色背景表示備份一張表的過程
2016-08-21T00:08:12.021499+08:00 15 Query use `dba_test` 2016-08-21T00:08:12.021549+08:00 15 Query select @@collation_database 2016-08-21T00:08:12.021616+08:00 15 Query SHOW TRIGGERS LIKE 'abc' ##備份觸發器,--triggers 2016-08-21T00:08:12.039445+08:00 15 Query SET SESSION character_set_results = 'utf8' 2016-08-21T00:08:12.039561+08:00 15 Query ROLLBACK TO SAVEPOINT sp ... ... 2016-08-21T00:23:35.131333+08:00 16 Query show events ##備份事件,-E 2016-08-21T00:23:35.161440+08:00 16 Query use `dba_test` 2016-08-21T00:23:35.161513+08:00 16 Query select @@collation_database 2016-08-21T00:23:35.161582+08:00 16 Query SET SESSION character_set_results = 'binary' 2016-08-21T00:23:35.161795+08:00 16 Query SHOW FUNCTION STATUS WHERE Db = 'dba_test' ##備份函數,-R 2016-08-21T00:23:35.190912+08:00 16 Query SHOW PROCEDURE STATUS WHERE Db = 'dba_test' ##備份存儲過程,-R 2016-08-21T00:23:35.191683+08:00 16 Query SET SESSION character_set_results = 'utf8'
2016-08-21T00:23:35.191683+08:00 16 Quit ##備份完成退出
3)實現過程
經過2)裏的general_log的這些步驟,能夠看到mysqldump的大體實現過程是:鏈接 -> 初始化信息 -> 刷新表(鎖表)-> 記錄偏移量 -> 開啓事務(一致性快照)-> 記錄偏移量 -> 解鎖表,由於開啓了一致性讀,能夠獲得innodb的一致性,又由於解鎖表了,MyISAM表一致性得不到保證,因此儘可能別使用MyISAM表。
關於xtrabackup的備份原理能夠看Percona XtraBackup 備份原理說明以及xtrabackup 使用說明(續)。這2篇文章已經講的很詳細了,本文就再也不進行說明。
根據本身的實際狀況,對備份原理、特性的認識,再選擇究竟是使用物理備份和邏輯備份。特別須要注意的是在用mysqldump備份時的一致性讀的時機(begin/start transaction 後面的第一條語句)。