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