天天看點

mysqldump和xtrabackup備份原理實作說明

MySQL資料庫備份分為邏輯備份和實體備份兩大類,猶豫到底用那種備份方式的時候先了解下它們的差異:

邏輯備份的特點是:直接生成SQL語句,在恢複的時候執行備份的SQL語句實作資料庫資料的重制。實體備份的特點是:拷貝相關資料檔案。

這二種備份差異  :邏輯備份其備份、還原慢,但備份檔案占用的空間小;實體備份其備份還原快,備份檔案占用空間大。
      

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

邏輯備份工具主要有:mysqldump、mysqlpump、mydumper,實體備份工具主要有: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=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

備份某個庫就鎖該庫的所有表,用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> 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)

+----+------+

| c1 | c2   |

|  1 |    1 |

1 row in set (0.00 sec)

結論1:RR隔離級别下的一緻性讀,不是以begin開始的時間點作為snapshot建立時間點,因為測試看出再begin一個事務的時候,表是沒有資料的,sessionB寫入資料之後,卻能看到資料。

測試2:

session A
mysql> select * from t;
Empty set (0.00 sec) 

結論2:RR隔離級别下的一緻性讀,是以第一條select語句的執行點作為snapshot建立的時間點的,即使是不同表的select語句。這裡因為session A在insert之前對 t 表執行了select,是以建立了snapshot,是以後面的select * from t1 不能讀取到insert的插入的值(snapshot的時候t1表沒有資料)。 

測試3: 

Empty set (0.01 sec)

結論3:session A 的第一條語句,發生在session B的 insert語句送出之前,是以session A中的第二條select還是不能讀取到資料。因為RR中的一緻性讀是以事務中第一個select語句執行的時間點作為snapshot建立的時間點的。而此時,session B的insert語句還沒有執行,是以讀取不到資料。

測試4:

mysql> insert into t1(c1,c2) values(1,1),(2,2);

|  2 |    2 |

2 rows in set (0.01 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

|  1 |  100 |

結論4:本事務中進行修改的資料,即使沒有送出,在本事務中的後面也可以讀取到。update 語句因為進行的是“目前讀”,是以它可以修改成功。

通過上面的幾個測試得出的結論:對同一個表或者不同表進行的第一次select語句建立了該事務中一緻性讀的snapshot,在snapshot建立之後送出的資料,一緻性讀就讀不到,之前送出的資料就可以讀到。事務一緻性讀的起始點其實是以執行的第一條語句為起始點的,而不是以begin作為事務的起始點的。

一般begin/start transaction是開始一個事務的标志,但不是事務開始的時間點,也就是說執行了start transaction之後的第一個語句(任何語句),事務才真正的開始。但是如果要達到将 start transaction作為事務開始的時間點,那麼必須使用: 

START TRANSACTION WITH consistent snapshot    ###mysqldump中的快照就是用這個實作的
      

這樣開啟事務效果等價于: start transaction 之後,馬上執行一條 select 語句(此時會建立一緻性讀的snapshot)。

測試5:

mysql> start transaction;

測試6: 

mysql> start transaction with consistent snapshot;

上面測試說明了 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備份步驟:

mysqldump和xtrabackup備份原理實作說明
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_MODE2016-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_NAME2016-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_NAME2016-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_test2016-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 tables2016-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=12016-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_database2016-08-21T00:08:12.021616+08:00   15 Query     SHOW TRIGGERS LIKE 'abc'                                ##備份觸發器,--triggers2016-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                                             ##備份事件,-E2016-08-21T00:23:35.161440+08:00   16 Query     use `dba_test`2016-08-21T00:23:35.161513+08:00   16 Query     select @@collation_database2016-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'              ##備份函數,-R2016-08-21T00:23:35.190912+08:00   16 Query     SHOW PROCEDURE STATUS WHERE Db = 'dba_test'             ##備份存儲過程,-R2016-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                                                              ##備份完成退出      
mysqldump和xtrabackup備份原理實作說明

繼續閱讀