mysqldump和xtrabackup備份原理實現說明


背景:

MySQL數據庫備份分為邏輯備份物理備份兩大類,猶豫到底用那種備份方式的時候先了解下它們的差異:

邏輯備份的特點是:直接生成SQL語句,在恢復的時候執行備份的SQL語句實現數據庫數據的重現。

物理備份的特點是:拷貝相關數據文件。

這二種備份差異 :邏輯備份其備份、還原慢,但備份文件占用的空間小;物理備份其備份還原快,備份文件占用空間大。

到底選擇那種備份方式,具體根據自己的實際情況,如需要的是熱備還是冷備?數據量大不大?磁盤空間夠不夠等因素決定。

邏輯備份工具主要有:mysqldumpmysqlpumpmydumper物理備份工具主要有:xtrabackup

現在使用最多的備份就是mysqldump、xtrabackup(都支持支持熱備),本文就mysqldump(mysqlpump)和xtrabackup的原理進行下大致的說明。

邏輯備份:mysqldump,第三方備份工具mydumper的備份原理看MySQL備份mydumper的原理

1)參數說明,具體的參數可以用mysqldump --help查看。

在說明mysqldump之前先了解下它的相關參數,可以通過mysqldump --help進行查看,也可以通過mysqldump、mysqlpump備份工具說明mysqldump的流程進行了解。這里再重申一下幾個比較重要的參數。

①:--single-transaction

通過將導出操作封裝在一個事務(Repeatable Read)內來使得導出的數據是一個一致性快照。只有當表使用支持MVCC的存儲引擎(目前只有InnoDB)時才可以工作;其他引擎不能保證導出是一致的。當導出開啟了–single-transaction選項時,要確保導出文件有效(正確的表數據和二進制日志位置),就要保證沒有其他連接會執行如下語句:ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,這會導致一致性快照失效。這個選項開啟后會自動關閉lock-tables。並且在mysql5.7.11之前,--default-parallelism大於1的時候和此參也互斥,必須使用--default-parallelism=05.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

備份某個庫就鎖該庫的所有表,用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)
 
測試6: 
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)
 
上面測試說明了 start transaction 和 start tansaction with consistent snapshot的區別測試5說明,start transaction執行之后,一致性讀並沒有開始,所以可以讀到session B插入的值。測試6說明,start transaction with consistent snapshot已經開始了一致性快照,所以insert語句發生在事務開始之后,所以讀不到insert的數據。

所以事務一致性快照開始時間點,分為兩種情況

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  ##刷新表,--master-data的作用 ##2016-08-21T00:08:11.815880+08:00 15 Query  FLUSH TABLES WITH READ LOCK  ##加全局讀鎖,--lock-all-tables的作用。 2016-08-21T00:08:11.815981+08:00   15 Query     SHOW STATUS LIKE 'binlog_snapshot_%' ##binlog的文件名和偏移量,--master-data的作用,或用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的作用,或用SHOW MASTER STATUS表示 2016-08-21T00:08:11.868940+08:00   15 Query UNLOCK TABLES   ##解鎖表,印證了全局讀鎖只會在開始dump的時候加上一小段時間 
#上面黃色背景表示備份前的一些准備工作:一致性快照、鎖、二進制日志等信息。

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

關於xtrabackup的備份原理可以看Percona XtraBackup 備份原理說明以及xtrabackup 使用說明(續)。這2篇文章已經講的很詳細了,本文就不再進行說明。

總結:

根據自己的實際情況,對備份原理、特性的認識,再選擇到底是使用物理備份和邏輯備份。特別需要注意的是在用mysqldump備份時的一致性讀的時機(begin/start transaction 后面的第一條語句)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM