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 后面的第一条语句)。