InnoDB存储引擎 (第8章 备份与恢复)

对于DBA来说,数据库的备份与恢复是一项最基本的操作与工作。在意外情况下(如服务器宕机、磁盘损坏、RAID卡损坏等)要保证数据不丢失,或者是最小程度地丢失,每个DBA应该每时每刻关心所负责的数据库备份情况。

本章主要介绍对InnoDB存储引擎的备份,应该知道MySQL数据库提供的大多数工具(如mysqldump、ibbackup、replication)都能很好地完成备份的工作,当然也可以通过第三方的一些工具来完成,如xtrabacup、LVM快照备份等。DBA应该根据自己的业务要求,设计出损失最小、对于数据库影响最小的备份策略。

8.1  备份与恢复概述

Hot Backup(热备)

Cold Backup(冷备)

Warm Backup(温备)

Hot Backup是指数据库运行中直接备份,对正在运行的数据库操作没有任何的影响。这种方式在MySQL官方手册中称为Online Backup(在线备份)。

Cold Backup是指备份操作是在数据库停止的情况下,这种备份最为简单,一般只需要复制相关的数据库物理文件即可。这种方式在MySQL官方手册中称为Offline Backup(离线备份)。

Warm Backup备份同样是在数据库运行中进行的,但是会对当前数据库的操作有所影响,如加一个全局读锁以保证备份数据的一致性。

按照备份后文件的内容,备份又可以分为:

逻辑备份

裸文件备份

在MySQL数据库中,逻辑备份是指备份出的文件内容是可读的,一般是文本文件。内容一般是由一条条SQL语句,或者是表内实际数据组成。如mysqldump和SELECT*INTO OUTFILE的方法。这类方法的好处是可以观察导出文件的内容,一般适用于数据库的升级、迁移等工作。但其缺点是恢复所需要的时间往往较长。

裸文件备份是指复制数据库的物理文件,既可以是在数据库运行中的复制(如ibbackup、xtrabackup这类工具),也可以是在数据库停止运行时直接的数据文件复制。这类备份的恢复时间往往较逻辑备份短很多。

若按照备份数据库的内容来分,备份又可以分为:

完全备份

增量备份

日志备份

完全备份是指对数据库进行一个完整的备份。

增量备份是指在上次完全备份的基础上,对于更改的数据进行备份。

日志备份主要是指对MySQL数据库二进制日志的备份,通过对一个完全备份进行二进制日志的重做(replay)来完成数据库的point-in-time的恢复工作。

MySQL数据库复制(replication)的原理就是异步实时地将二进制日志重放(replay)传送并应用到从(slave/standby)数据库。

增量备份过程

对于真正的增量备份来说,只需要记录当前每页最后的检查点的LSN,如果大于之前全备时的LSN,则备份该页,否则不用备份,这大大加快了备份的速度和恢复的时间,同时这也是xtrabackup工具增量备份的原理。

一致性备份

对于InnoDB存储引擎来说,因为其支持MVCC功能,因此实现一致的备份比较简单。用户可以先开启一个事务,然后导出一组相关的表,最后提交。当然用户的事务隔离级别必须设置为REPEATABLE READ,这样的做法就可以给出一个完美的一致性备份。

对于mysqldump备份工具来说,可以通过添加--single-transaction选项获得InnoDB存储引擎的一致性备份,原理和之前所说的相同。需要了解的是,这时的备份是在一个执行时间很长的事务中完成的。另外,对于InnoDB存储引擎的备份,务必加上--single-transaction的选项

8.2  冷备

冷备的优点是:

备份简单,只要复制相关文件即可。

备份文件易于在不同操作系统,不同MySQL版本上进行恢复。

恢复相当简单,只需要把文件恢复到指定位置即可。

恢复速度快,不需要执行任何SQL语句,也不需要重建索引。

冷备的缺点是:

InnoDB存储引擎冷备的文件通常比逻辑文件大很多,因为表空间中存放着很多其他的数据,如undo段,插入缓冲等信息。

冷备也不总是可以轻易地跨平台。操作系统、MySQL的版本、文件大小写敏感和浮点数格式都会成为问题。

8.3  逻辑备份

8.3.1 mysqldump

通常用来完成转存(dump)数据库的备份及不同数据库之间的移植,如从MySQL低版本数据库升级到MySQL高版本数据库,又或者从MySQL数据库移植到Oracle、Microsoft SQL Server数据库等。

mysqldump的语法如下:

shell>mysqldump[arguments]>fle_name

如果想要备份所有的数据库,可以使用--all-databases选项:

*shell>mysqldump--all-databases>dump.sql

如果想要备份指定的数据库,可以使用--databases选项:

*shell>mysqldump--databases db1 db2 db3>dump.sql

如果想要对test这个架构进行备份,可以使用如下语句:

*[root@xen-server~]#mysqldump--single-transaction test>test_backup.sql

参数选项

mysqldump的参数选项很多,可以通过使用mysqldump--help命令来查看所有的参数,有些参数有缩写形式,如--lock-tables的缩写形式-l。这里列举一些比较重要的参数。

--single-transaction:在备份开始前,先执行START TRANSACTION命令,以此来获得备份的一致性,当前该参数只对InnoDB存储引擎有效。当启用该参数并进行备份时,确保没有其他任何的DDL语句执行,因为一致性读并不能隔离DDL操作。

--lock-tables(-l):在备份中,依次锁住每个架构下的所有表。一般用于MyISAM存储引擎,当备份时只能对数据库进行读取操作,不过备份依然可以保证一致性。对于InnoDB存储引擎,不需要使用该参数,用--single-transaction即可。并且--lock-tables和--single-transaction是互斥(exclusive)的,不能同时使用。如果用户的MySQL数据库中,既有MyISAM存储引擎的表,又有InnoDB存储引擎的表,那么这时用户的选择只有--lock-tables了。此外,正如前面所说的那样,--lock-tables选项是依次对每个架构中的表上锁的,因此只能保证每个架构下表备份的一致性,而不能保证所有架构下表的一致性

--lock-all-tables(-x):在备份过程中,对所有架构中的所有表上锁。这个可以避免之前说的--lock-tables参数不能同时锁住所有表的问题。

--add-drop-database:在CREATE DATABASE前先运行DROP DATABASE。这个参数需要和--all-databases或者--databases选项一起使用。在默认情况下,导出的文本文件中并不会有CREATE DATABASE,除非指定了这个参数,因此可能会看到如下的内容:

*[root@xen-server~]#mysqldump--single-transaction--add-drop-database--databases test>test_backup.sql

[root@xen-server~]#cat test_backup.sql

--MySQL dump 10.13 Distrib 5.5.1-m2,for unknown-linux-gnu(x86_64)

……

--

--Current Database:'test'

--

/*!40000 DROP DATABASE IF EXISTS'test'*/;

CREATE DATABASE/*!32312 IF NOT EXISTS*/'test'/*!40100 DEFAULT CHARACTER SET latin1*/;

USE'test';

……

*--master-data[=value]:通过该参数产生的备份转存文件主要用来建立一个replication。当value的值为1时,转存文件中记录CHANGE MASTER语句。当value的值为2时,CHANGE MASTER语句被写出SQL注释。在默认情况下,value的值为空。当value值为1时,在备份文件中会看到:

*[root@xen-server~]#mysqldump--single-transaction--add-drop-database--master-data=1--databases test>test_backup.sql

[root@xen-server~]#cat test_backup.sql

--MySQL dump 10.13 Distrib 5.5.1-m2,for unknown-linux-gnu(x86_64)

--

--Host:localhost Database:test

--------------------------------------------------------

--Server version 5.5.1-m2-log

……

--

--Position to start replication or point-in-time recovery from

--

CHANGE MASTER TO MASTER_LOG_FILE='xen-server-bin.000006',MASTER_LOG_POS=8095;

……

*当value为2时,在备份文件中会看到CHANGE MASTER语句被注释了:

*[root@xen-server~]#mysqldump--single-transaction--add-drop-database--master-data=2--databases test>test_backup.sql

[root@xen-server~]#cat test_backup.sql

--MySQL dump 10.13 Distrib 5.5.1-m2,for unknown-linux-gnu(x86_64)

--

--Host:localhost Database:test

--------------------------------------------------------

--Server version 5.5.1-m2-log

……

--

--Position to start replication or point-in-time recovery from

--

--

……

*--master-data会自动忽略--lock-tables选项。如果没有使用--single-transaction选项,则会自动使用--lock-all-tables选项。

--events(-E):备份事件调度器。

--routines(-R):备份存储过程和函数。

--triggers:备份触发器。

--hex-blob:将BINARY、VARBINARY、BLOG和BIT列类型备份为十六进制的格式。mysqldump导出的文件一般是文本文件,但是如果导出的数据中有上述这些类型,在文本文件模式下可能有些字符不可见,若添加--hex-blob选项,结果会以十六进制的方式显示,如:

*[root@xen-server~]#mysqldump--single-transaction--add-drop-database--master-data=2--no-autocommit--databases test3>test3_backup.sql

[root@xen-server~]#cat test3_backup.sql

--MySQL dump 10.13 Distrib 5.5.1-m2,for unknown-linux-gnu(x86_64)

--

--Host:localhost Database:test3

--------------------------------------------------------

--Server version 5.5.1-m2-log

……

LOCK TABLES'a'WRITE;

/*!40000 ALTER TABLE'a'DISABLE KEYS*/;

setautocommit=0;

INSERT INTO'a'VALUES(0x61000000000000000000);

/*!40000 ALTER TABLE'a'ENABLE KEYS*/;

UNLOCK TABLES;

*可以看到,这里用0x61000000000000000000的十六进制的格式来导出数据。

--tab=path(-T path):产生TAB分割的数据文件。对于每张表,mysqldump创建一个包含CREATE TABLE语句的table_name.sql文件,和包含数据的tbl_name.txt文件。可以使用--fields-terminated-by=...,--fields-enclosed-by=...,--fields-optionally-enclosed-by=...,--fields-escaped-by=...,--lines-terminated-by=...来改变默认的分割符、换行符等。如:

*[root@xen-server test]#mysqldump--single-transaction--add-drop-database--tab="/usr/local/mysql/data/test"test

[root@xen-server test]#ls-lh

total 244K

-rw-rw----1 mysql mysql 8.4K Jul 21 16:02 a.frm

-rw-rw----1 mysql mysql 96K Jul 22 17:18 a.ibd

-rw-r--r--1 root root 1.3K Aug 3 15:36 a.sql

-rw-rw-rw-1 mysql mysql 8 Aug 3 15:36 a.txt

-rw-rw----1 mysql mysql 65 Jul 17 15:54 db.opt

-rw-rw----1 mysql mysql 8.4K Aug 2 17:22 z.frm

-rw-rw----1 mysql mysql 96K Aug 2 17:22 z.ibd

-rw-r--r--1 root root 1.3K Aug 3 15:36 z.sql

-rw-rw-rw-1 mysql mysql 4 Aug 3 15:36 z.txt

-----------

--Server version 5.5.1-m2-log

/*!40101 SET@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT*/;

/*!40101 SET@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS*/;

/*!40101 SET@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION*/;

/*!40101 SET NAMES utf8*/;

/*!40103 SET@OLD_TIME_ZONE=@@TIME_ZONE*/;

/*!40103 SET TIME_ZONE='+00:00'*/;

/*!40101 SET@OLD_SQL_MODE=@@SQL_MODE,SQL_MODE=''*/;

/*!40111 SET@OLD_SQL_NOTES=@@SQL_NOTES,SQL_NOTES=0*/;

--

--Table structure for table'a'

--

DROP TABLE IF EXISTS'a';

/*!40101 SET@saved_cs_client=@@character_set_client*/;

/*!40101 SET character_set_client=utf8*/;

CREATE TABLE'a'(

'b'int(11)NOT NULL DEFAULT'0',

PRIMARY KEY('b')

)ENGINE=InnoDB DEFAULT CHARSET=latin1;

/*!40101 SET character_set_client=@saved_cs_client*/;

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE*/;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE*/;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT*/;

/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS*/;

/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION*/;

/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES*/;

--Dump completed on 2010-08-03 15:36:56

[root@xen-server test]#cat a.txt

1

2

4

5

*我发现大多数DBA喜欢用SELECT...INTO OUTFILE的方式来导出一张表,但是通过mysqldump一样可以完成工作,而且可以一次完成多张表的导出,并且实现导出数据的一致性。

--where='where_condition'(-w'where_condition'):导出给定条件的数据。如导出b架构下的表a,并且表a的数据大于2:

*[root@xen-server bin]#mysqldump--single-transaction--where='b>2'test a>a.sql

[root@xen-server bin]#cat a.sql

--MySQL dump 10.13 Distrib 5.5.1-m2,for unknown-linux-gnu(x86_64)

--

--Host:localhost Database:test

--------------------------------------------------------

--Server version 5.5.1-m2-log

……

--

--Dumping data for table'a'

--

--WHERE:b>2

LOCK TABLES'a'WRITE;

/*!40000 ALTER TABLE'a'DISABLE KEYS*/;

INSERT INTO'a'VALUES(4),(5);

/*!40000 ALTER TABLE'a'ENABLE KEYS*/;

UNLOCK TABLES;

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE*/;

……

8.3.2 SELECT...INTO OUTFILE

SELECT...INTO语句也是一种逻辑备份的方法,更准确地说是导出一张表中的数据。SELECT...INTO的语法如下:

SELECT[column 1],[column 2]...

INTO

OUTFILE'file_name'

[{FIELDS|COLUMNS}

[TERMINATED BY'string']

[[OPTIONALLY]ENCLOSED BY'char']

[ESCAPED BY'char']

]

[LINES

[STARTING BY'string']

[TERMINATED BY'string']

]

FROM TABLE WHERE......

FIELDS [TERMINATED BY'string']表示每个列的分隔符,

[[OPTIONALLY]ENCLOSED BY'char']表示对于字符串的包含符,

[ESCAPED BY'char']表示转义符。

[STARTING BY'string']表示每行的开始符号,

TERMINATED BY'string'表示每行的结束符号。

如果没有指定任何的FIELDS和LINES的选项,默认使用以下的设置:

FIELDS TERMINATED BY' 'ENCLOSED BY''ESCAPED BY'\'

LINES TERMINATED BY' 'STARTING BY'' ;

file_name表示导出的文件,但文件所在的路径的权限必须是mysql∶mysql的,否则MySQL会报没有权限导出:

mysql>select*into outfile'/root/a.txt'from a;

ERROR 1(HY000):Can't create/write to file'/root/a.txt'(Errcode:13)

若已经存在该文件,则同样会报错:

[root@xen-server~]#mysql test-e"select*into outfile'/home/mysql/a.txt'fields terminated by','from a";

ERROR 1086(HY000)at line 1:File'/home/mysql/a.txt'already exists

查看通过SELECT INTO导出的表a文件:

mysql>select*into outfile'/home/mysql/a.txt'from a;

Query OK,3 rows affected(0.02 sec)

mysql>quit

Bye

[root@xen-server~]#cat/home/mysql/a.txt

1 a

2 b

3 c

可以发现,默认导出的文件是以TAB进行列分割的,如果想要使用其他分割符,如",",则可以使用FIELDS TERMINATED BY'string'选项,如:

[root@xen-server~]#mysql test-e"select*into outfile'/home/mysql/a.txt'fields terminated by','from a";

[root@xen-server~]#cat/home/mysql/a.txt

1,a

2,b

3,c

在Windows平台下,由于换行符是" ",因此在导出时可能需要指定LINES TERMINATED BY选项,如:

[root@xen-servermysql]#mysql test-e"select*into outfile'/home/mysql/a.txt'fields terminated by','lines terminated by' 'from a";

[root@xen-servermysql]#od-c a.txt

0000000 1,a 2,b 3,c

0000017

8.3.3 逻辑备份的恢复

mysqldump的恢复操作比较简单,因为备份的文件就是导出的SQL语句,一般只需要执行这个文件就可以了,可以通过以下的方法:

[root@xen-server~]#mysql-uroot-p<test_backup.sql

Enter password:

因为逻辑备份的文件是由SQL语句组成的,也可以通过SOURCE命令来执行导出的逻辑备份文件,如下:

mysql>source/home/mysql/test_backup.sql;

通过mysqldump可以恢复数据库,但是经常发生的一个问题是,mysqldump可以导出存储过程、导出触发器、导出事件、导出数据,但是却不能导出视图。因此,如果用户的数据库中还使用了视图,那么在用mysqldump备份完数据库后还需要导出视图的定义,或者备份视图定义的frm文件,并在恢复时进行导入,这样才能保证mysqldump数据库的完全恢复。

8.3.4 LOAD DATA INFILE

若通过mysqldump-tab,或者通过 SELECT INTO OUTFILE导出的数据需要恢复,这时可以通过命令LOAD DATA INFILE来进行导入。LOAD DATA INFILE的语法如下:

LOAD DATA INTO TABLE a IGNORE 1 LINES INFILE'/home/mysql/a.txt'

[REPLACE|IGNORE]

INTO TABLE tbl_name

[CHARACTER SET charset_name]

[{FIELDS|COLUMNS}

[TERMINATED BY'string']

[[OPTIONALLY]ENCLOSED BY'char']

[ESCAPED BY'char']

]

[LINES

[STARTING BY'string']

[TERMINATED BY'string']

]

[IGNORE number LINES]

[(col_name_or_user_var,...)]

[SET col_name=expr,...]

要对服务器文件使用LOAD DATA INFILE,必须拥有FILE权。其中对于导入格式的选项和之前介绍的SELECT INTO OUTFILE命令完全一样。

IGNORE number LINES选项可以忽略导入的前几行。

下面显示一个用LOAD DATA INFILE命令导入文件的示例,并忽略第一行的导入:

mysql>load data infile'/home/mysql/a.txt'into table a;

为了加快InnoDB存储引擎的导入,可能希望导入过程忽略对外键的检查,因此可以使用如下方式:

mysql>SET@@foreign_key_checks=0;

Query OK,0 rows affected(0.00 sec)

mysql>LOAD DATA INFILE'/home/mysql/a.txt'INTO TABLE a;

Query OK,4 rows affected(0.00 sec)

Records:4 Deleted:0 Skipped:0 Warnings:0

mysql>SET@@foreign_key_checks=1;

Query OK,0 rows affected(0.00 sec)

另外可以针对指定的列进行导入,如将数据导入列a、b,而c列等于a、b列之和:

mysql>CREATE TABLE b(

->a INT,

->b INT,

->c INT,

->PRIMARY KEY(a)

->)ENGINE=InnoDB;

Query OK,0 rows affected(0.01 sec)

mysql>LOAD DATA INFILE'/home/mysql/a.txt'

->INTO TABLE b FIELDS TERMINATED BY','(a,b)

->SET c=a+b;

Query OK,4 rows affected(0.01 sec)

Records:4 Deleted:0 Skipped:0 Warnings:0

mysql>SELECT*FROM b;

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

|a|b|c|

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

|1|2|3|

|2|3|5|

|4|5|9|

|5|6|11|

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

4 rows in set(0.00 sec)

8.3.5 mysqlimport

mysqlimport是MySQL数据库提供的一个命令行程序,从本质上来说,是LOAD DATA INFILE的命令接口,而且大多数的选项都和LOAD DATA INFILE语法相同。其语法格式如下:

mysqlimport[options]db_name textfile1 [textfile2...]

和LOAD DATA INFILE不同的是,mysqlimport命令可以用来导入多张表。并且通过--user-thread参数并发地导入不同的文件。这里的并发是指并发导入多个文件,而不是指mysqlimport可以并发地导入一个文件,这是有明显区别的。此外,通常来说并发地对同一张表进行导入,其效果一般都不会比串行的方式好。下面通过mysqlimport并发地导入2张表:

mysqlimport--use-threads=2 test/home/mysql/t.txt /home/mysql/s.txt

8.4  二进制日志备份与恢复

二进制日志非常关键,用户可以通过它完成point-in-time的恢复工作。MySQL数据库的replication同样需要二进制日志。在默认情况下并不启用二进制日志,要使用二进制日志首先必须启用它。如在配置文件中进行设置:

[mysqld]

log-bin=mysql-bin

对于InnoDB存储引擎只简单启用二进制日志是不够的,还需要启用一些其他参数来保证最为安全和正确地记录二进制日志,因此对于InnoDB存储引擎,推荐的二进制日志的服务器配置应该是:

[mysqld]

log-bin=mysql-bin

sync_binlog=1

innodb_support_xa=1

在备份二进制日志文件前,可以通过FLUSH LOGS命令来生成一个新的二进制日志文件,然后备份之前的二进制日志。

要恢复二进制日志也是非常简单的,通过mysqlbinlog即可。mysqlbinlog的使用方法如下:

shell>mysqlbinlog [options] log_fle...

例如要还原binlog.0000001,可以使用如下命令:

shell>mysqlbinlog binlog.0000001 | mysql-uroot -p test

如果需要恢复多个二进制日志文件,最正确的做法应该是同时恢复多个二进制日志文件,而不是一个一个地恢复 ;

--start-position和--stop-position选项可以用来指定从二进制日志的某个偏移量来进行恢复,这样可以跳过某些不正确的语句,如:

shell>mysqlbinlog --start-position=107856 binlog.0000001 | mysql -uroot -p test

--start-datetime和--stop-datetime选项可以用来指定从二进制日志的某个时间点来进行恢复,用法和--start-position和--stop-position选项基本相同。

8.5  热备

8.5.1 ibbackup

ibbackup是InnoDB存储引擎官方提供的热备工具,可以同时备份MyISAM存储引擎和InnoDB存储引擎表。

对于InnoDB存储引擎表其备份工作原理如下:

1)记录备份开始时,InnoDB存储引擎重做日志文件检查点的LSN。

2)复制共享表空间文件以及独立表空间文件

3)记录复制完表空间文件后,InnoDB存储引擎重做日志文件检查点的LSN。

4)复制在备份时产生的重做日志

对于事务的数据库,如Microsoft SQL Server数据库和Oracle数据库,热备的原理大致和上述相同。可以发现,在备份期间不会对数据库本身有任何影响,所做的操作只是复制数据库文件,因此任何对数据库的操作都是允许的,不会阻塞任何操作。

故ibbackup的优点如下:

在线备份,不阻塞任何的SQL语句。

备份性能好,备份的实质是复制数据库文件和重做日志文件。

支持压缩备份,通过选项,可以支持不同级别的压缩。

跨平台支持,ibbackup可以运行在Linux、Windows以及主流的UNIX系统平台上。

ibbackup对InnoDB存储引擎表的恢复步骤为:

恢复表空间文件。

应用重做日志文件。

ibbackup提供了一种高性能的热备方式,是InnoDB存储引擎备份的首选方式。不过它是收费软件,并非免费的软件。好在开源的魅力就在于社区的力量,Percona公司给用户带来了开源、免费的XtraBackup热备工具,它实现所有ibbackup的功能,并且扩展支持了真正的增量备份功能。因此,更好的选择是使用XtraBackup来完成热备的工作。

8.5.2 XtraBackup

XtraBackup备份工具是由Percona公司开发的开源热备工具。支持MySQL5.0以上的版本。XtraBackup在GPL v2开源下发布,官网地址是:https://launchpad.net/percona-xtrabackup。

xtrabackup命令的使用方法如下:

xtrabackup--backup | --prepare [OPTIONS]

Xtrabackup备份原理

1innobackupex启动后,会先fork一个进程,用于启动xtrabackup,然后等待xtrabackup备份ibd数据文件;

2xtrabackup在备份innoDB数据是,有2种线程:redo拷贝线程ibd数据拷贝线程xtrabackup进程开始执行后,会启动一个redo拷贝的线程,用于从最新的checkpoint点开始顺序拷贝redo.log;再启动ibd数据拷贝线程,进行拷贝ibd数据。这里是先启动redo拷贝线程的。在此阶段,innobackupex进行处于等待状态(等待文件被创建)

4xtrabackup拷贝完成ibd数据文件后,会通知innobackupex(通过创建文件),同时xtrabackup进入等待状态(redo线程依旧在拷贝redo.log

5innobackupex收到xtrabackup通知后哦,执行FLUSH TABLES WITH READ LOCKFTWRL,取得一致性位点,然后开始备份非InnoDB文件(如frmMYDMYICSVoptpar等格式的文件),在拷贝非InnoDB文件的过程当中,数据库处于全局只读状态。

6)当innobackup拷贝完所有的非InnoDB文件后,会通知xtrabackup,通知完成后,进入等待状态;

7xtrabackup收到innobackupex备份完成的通知后,会停止redo拷贝线程,然后通知innobackupexredo.log文件拷贝完成;

8innobackupex收到redo.log备份完成后,就进行解锁操作,执行:UNLOCK TABLES

9)最后innbackupexxtrabackup进程各自释放资源,写备份元数据信息等,innobackupexxtrabackup子进程结束后退出。

8.5.3 XtraBackup实现增量备份

MySQL数据库本身提供的工具并不支持真正的增量备份,更准确地说,二进制日志的恢复应该是point-in-time的恢复而不是增量备份。

而XtraBackup工具支持对于InnoDB存储引擎的增量备份,其工作原理如下:

1)首选完成一个全备,并记录下此时检查点的LSN。

2)在进行增量备份时,比较表空间中每个页的LSN是否大于上次备份时的LSN,如果是,则备份该页,同时记录当前检查点的LSN。

8.6  快照备份

MySQL数据库本身并不支持快照功能,因此快照备份是指通过文件系统支持的快照功能对数据库进行备份。备份的前提是将所有数据库文件放在同一文件分区中,然后对该分区进行快照操作。支持快照功能的文件系统和设备包括FreeBSD的UFS文件系统,Solaris的ZFS文件系统,GNU/Linux的逻辑管理器(Logical Volume Manager,LVM)等。这里以LVM为例进行介绍,UFS和ZFS的快照实现大致和LVM相似。

LVM是LINUX系统下对磁盘分区进行管理的一种机制。LVM在硬盘和分区之上建立一个逻辑层,来提高磁盘分区管理的灵活性。管理员可以通过LVM系统轻松管理磁盘分区,例如,将若干个磁盘分区连接为一个整块的卷组(Volume Group),形成一个存储池。管理员可以在卷组上随意创建逻辑卷(Logical Volumes),并进一步在逻辑卷上创建文件系统。管理员通过LVM可以方便地调整卷组的大小,并且可以对磁盘存储按照组的方式进行命名、管理和分配。

简单地说,用户可以通过LVM由物理块设备(如硬盘等)创建物理卷,由一个或多个物理卷创建卷组,最后从卷组中创建任意个逻辑卷(不超过卷组大小),如图8-1所示。

图8-2显示了由多块磁盘组成的逻辑卷LV0。

通过vgdisplay命令查看系统中有哪些卷组,如:

[root@nh124-98~]# vgdisplay

命令lvdisplay可以用来查看当前系统中有哪些逻辑卷:

[root@nh124-98~]# lvdisplay

写时复制

LVM使用了写时复制(Copy-on-write)技术来创建快照。当创建一个快照时,仅复制原始卷中数据的元数据(meta data),并不会有数据的物理操作,因此快照的创建过程是非常快的。当快照创建完成,原始卷上有写操作时,快照会跟踪原始卷块的改变,将要改变的数据在改变之前复制到快照预留的空间里,因此这个原理的实现叫做写时复制。而对于快照的读取操作,如果读取的数据块是创建快照后没有修改过的,那么会将读操作直接重定向到原始卷上,如果要读取的是已经修改过的块,则将读取保存在快照中该块在原始卷上改变之前的数据。因此,采用写时复制机制保证了读取快照时得到的数据与快照创建时一致。

图8-3显示了LVM的快照读取,可见B区块被修改了,因此历史数据放入了快照区域。读取快照数据时,A、C、D块还是从原有卷中读取,而B块就需要从快照读取了。

用LVM快照备份InnoDB存储引擎表相当简单,只要把与InnoDB存储引擎相关的文件如共享表空间、独立表空间、重做日志文件等放在同一个逻辑卷中,然后对这个逻辑卷做快照备份即可。

在对InnoDB存储引擎文件做快照时,数据库无须关闭,即可以进行在线备份。虽然此时数据库中可能还有任务需要往磁盘上写数据,但这不会妨碍备份的正确性。因为InnoDB存储引擎是事务安全的引擎,在下次恢复时,数据库会自动检查表空间中页的状态,并决定是否应用重做日志,恢复就好像数据库被意外重启了。

8.7  复制

8.7.1 复制的工作原理

复制(replication)是MySQL数据库提供的一种高可用高性能的解决方案,一般用来建立大型的应用。总体来说,replication的工作原理分为以下3个步骤:

1)主服务器(master)把数据更改记录到二进制日志(binlog)中。

2)从服务器(slave)把主服务器的二进制日志复制到自己的中继日志(relay log)中。

3)从服务器重做中继日志中的日志,把更改应用到自己的数据库上,以达到数据的最终一致性。

复制的工作原理并不复杂,其实就是一个完全备份加上二进制日志备份的还原。不同的是这个二进制日志的还原操作基本上实时在进行中。这里特别需要注意的是,复制不是完全实时地进行同步,而是异步实时。这中间存在主从服务器之间的执行延时,如果主服务器的压力很大,则可能导致主从服务器延时较大。复制的工作原理如图8-4所示。

从服务器有2个线程,一个是I/O线程,负责读取主服务器的二进制日志,并将其保存为中继日志;另一个是SQL线程,复制执行中继日志。MySQL4.0版本之前,从服务器只有1个线程,既负责读取二进制日志,又负责执行二进制日志中的SQL语句。这种方式不符合高性能的要求,目前已淘汰。因此如果查看一个从服务器的状态,应该可以看到类似如下内容:

mysql>SHOW FULL PROCESSLISTG;

MySQL的复制是异步实时的,并非完全的主从同步。若用户要想得知当前的延迟,可以通过命令 SHOW SLAVE STATUS 和 SHOW MASTER STATUS 得知;

当前二进制日志记录了偏移量的位置,该值减去这一时间点时从服务器上的Read_Master_Log_Pos,就可以得知I/O线程的延时。

8.7.2 快照+复制的备份架构

复制可以用来作为备份,但功能不仅限于备份,其主要功能如下:

数据分布。由于MySQL数据库提供的复制并不需要很大的带宽要求,因此可以在不同的数据中心之间实现数据的复制。

读取的负载平衡。通过建立多个从服务器,可将读取平均地分布到这些从服务器中,并且减少了主服务器的压力。一般通过DNS的Round-Robin和Linux的LVS功能都可以实现负载平衡。

数据库备份。复制对备份很有帮助,但是从服务器不是备份,不能完全代替备份。

高可用性和故障转移。通过复制建立的从服务器有助于故障转移,减少故障的停机时间和恢复时间。

可见,复制的设计不是简简单单用来备份的,并且只是用复制来进行备份是远远不够的。假设当前应用采用了主从的复制架构,从服务器作为备份。这时,一个初级DBA执行了误操作,如DROP DATABASE或DROP TABLE,这时从服务器也跟着运行了。这时用户怎样从服务器进行恢复呢?

因此,一个比较好的方法是通过对从服务器上的数据库所在分区做快照,以此来避免误操作对复制造成影响。当发生主服务器上的误操作时,只需要将从服务器上的快照进行恢复,然后再根据二进制日志进行point-in-time的恢复即可。因此快照+复制的备份架构如图8-5所示。

还有一些其他的方法来调整复制,比如采用延时复制,即间歇性地开启从服务器上的同步,保证大约一小时的延时。这的确也是一个方法,只是数据库在高峰和非高峰期间每小时产生的二进制日志量是不同的,用户很难精准地控制。另外,这种方法也不能完全起到对误操作的防范作用。

此外,建议在从服务上启用read-only选项,这样能保证从服务器上的数据仅与主服务器进行同步,避免其他线程修改数据。

8.8  小结

原文地址:https://www.cnblogs.com/coloz/p/13792693.html