mysqldump的原理:

mysqldump是当前MySQL中最常用的备份工具,mysqldump产生的备份,最终是要结合binlog进行恢复。mysqldump也可以准确得到binlog的恢复点。

那么mysqldump中如何保证数据一致性并生成备份的呢?下面通过一个常用示例来解释mysqldump的原理。(仅针对InnoDB存储引擎举例)


创建测试库、表,并插入数据


mysql -uroot -poracle -S/tmp/mysql.sock -e'create database test_bak;'


mysql -uroot -poracle -S/tmp/mysql.sock -e'create table test_bak.test (id int);'


mysql -uroot -poracle -S/tmp/mysql.sock -e'insert into test_bak.test values(1),(2),(3),(4),(5);'


mysql -uroot -poracle -S/tmp/mysql.sock -e'select * from test_bak.test;'


+------+


| id   |


+------+


|    1 |


|    2 |


|    3 |


|    4 |


|    5 |


+------+



开启general.log:


mysql> show global variables like "%genera%";


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


| Variable_name    | Value                     |


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


| general_log      | OFF                       |


| general_log_file | /mysql/data/localhost.log |


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


2 rows in set (0.00 sec)



mysql> set global general_log=on;


Query OK, 0 rows affected (0.02 sec)



mysql> show global variables like "%genera%";


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


| Variable_name    | Value                     |


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


| general_log      | ON                        |


| general_log_file | /mysql/data/localhost.log |


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


2 rows in set (0.01 sec)




mysqldump导出test_bak的数据:


/usr/local/mysql/bin/mysqldump -uroot -poracle -R --single-transaction --master-data=2 -S/tmp/mysql.sock -B test_bak  > /mysql/backup/bak.sql



查看/mysql/data/localhost.log:


160525 20:54:14    13 Connect   root@localhost on


                   13 Query     /*!40100 SET @@SQL_MODE='' */


                   13 Query     /*!40103 SET TIME_ZONE='+00:00' */


                   13 Query     FLUSH /*!40101 LOCAL */ TABLES


                   13 Query     FLUSH TABLES WITH READ LOCK


                   13 Query     SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ


                   13 Query     START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */


                   13 Query     SHOW VARIABLES LIKE 'gtid\_mode'


                   13 Query     SHOW MASTER STATUS


                   13 Query     UNLOCK TABLES


                   13 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 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 ('test_bak'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE ORDER BY LOGFILE_GROUP_NAME


                   13 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 ('test_bak')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME


                   13 Query     SHOW VARIABLES LIKE 'ndbinfo\_version'


                   13 Init DB   test_bak


                   13 Query     SHOW CREATE DATABASE IF NOT EXISTS `test_bak`


                   13 Query     SAVEPOINT sp


                   13 Query     show tables


                   13 Query     show table status like 'test'


                   13 Query     SET SQL_QUOTE_SHOW_CREATE=1


                   13 Query     SET SESSION character_set_results = 'binary'


                   13 Query     show create table `test`


                   13 Query     SET SESSION character_set_results = 'utf8'


                   13 Query     show fields from `test`


                   13 Query     SELECT /*!40001 SQL_NO_CACHE */ * FROM `test`


                   13 Query     SET SESSION character_set_results = 'binary'


                   13 Query     use `test_bak`


                   13 Query     select @@collation_database


                   13 Query     SHOW TRIGGERS LIKE 'test'


                   13 Query     SET SESSION character_set_results = 'utf8'


                   13 Query     ROLLBACK TO SAVEPOINT sp


                   13 Query     RELEASE SAVEPOINT sp


                   13 Query     use `test_bak`


                   13 Query     select @@collation_database


                   13 Query     SET SESSION character_set_results = 'binary'


                   13 Query     SHOW FUNCTION STATUS WHERE Db = 'test_bak'


                   13 Query     SHOW PROCEDURE STATUS WHERE Db = 'test_bak'


                   13 Query     SET SESSION character_set_results = 'utf8'


                   13 Quit



第一行,执行connect是通过mysqldump选项中的-u, -p, -S来进行端口、用户验证,然后连接服务器。



其中的flush tables 、flush tables with read lock、 unlock tables及其中的show master status是响应选项--master-data.


通过一个瞬间的锁表,利用show master status来得到binlog的位置。在backup.sql中,可以找到类似下面的信息。


-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=2154;



进行瞬间的锁表就是要保证得到正确的binlog位置。flush tables后,当前数据库快照就是我们要备份的,


通过show master status得到binlog位置信息。那么如何保证对当前数据库快照进行备份呢?


结合选项--single-transaction,mysqldump的处理是start transaction。由于INNODB的MVCC机制,


start transacion会产生一个事务id,利用这个事务id可以过滤该事务之后的事务对数据库的更新操作,


从而得到当前快照的备份。



有个细节要注意,flush tables ;flush tables with read lock; 为什么不直接就加上read lock,这样写的好处是什么?


其实这样做可以尽可能少的减少加锁的影响,减少冲突。



另一个细节要注意是start transaction要放在flush tables 与 unlock tables之间,不能放在前面或者后面。


flush tables后,当前数据库快照就是我们要备份的,然后show master status也得到了binlog位置信息。


而start transaction是通过begin一个事务来获取这个快照的,如果放在前面或者后面,会造成数据丢失或者数据的重复插入。



另外,还有很多general log信息,来得到当前快照中的数据库、表、存储过程及数据等。下面仅以test库中一个t1表的部分内容为例说明。


SHOW CREATE DATABASE IF NOT EXISTS `test_bak`; 服务器响应该语句得到test_bak库的创建语句


SHOW CREATE DATABASE IF NOT EXISTS `test_bak` 加上if not exists保证在create时不存在test_bak库才创建test_bak。


show tables 获取test库中所有的表。


show table status like ‘test’ 得到test表的状态信息,便于进一步处理。


show create table `test` 生成test表的创建语句。


SELECT /*!40001 SQL_NO_CACHE */ * FROM `test` 该语句得到表t1的所有数据,在backup.sql中会生成相应的insert语句,


恢复时执行这些数据的insert操作。其中sql_no_cache的作用是避免查询结果缓存(不是不在缓存中查询结果)。



在general log中还可以看到一系列mysqldump处理后发送到服务器的语句,然后mysqldump利用服务器返回的结果进行处理,


从而得到备份文件bak.sql