当前位置:嗨网首页>书籍在线阅读

10-热备份

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

在 MySQL 中,对于不同的存储引擎热备份方法也有所不同,下面主要介绍 MyISAM 和InnoDB两种最常用的存储引擎的热备份方法。

1.MyISAM存储引擎

MyISAM 存储引擎的热备份有很多方法,本质其实就是将要备份的表加读锁,然后再 cp数据文件到备份目录。常用的有以下两种方法。

方法1:使用mysqlhotcopy工具。

mysqlhotcopy是MySQL自带的一个热备份工具,使用方法很简单:

shell > mysqlhotcopy db_name [/path/to/new_directory]

mysqlhotcopy有很多选项,具体可以使用“--help”查看帮助:

mysqlhotcopy –help

方法2:手工锁表copy。

在mysqlhotcopy使用不正常的情况下,可以手工来做热备份,操作步骤如下。

首先数据库中所有表加读锁:

mysql>flush tables for read ;

然后cp数据文件到备份目录即可。

2.InnoDB存储引擎

ibbackup是Innobase公司(www.innodb.com)的一个热备份工具,专门对InnoDB存储引擎进行物理热备份,此工具是收费的,但可以免费使用1个月。Innobase公司已经于2005年被Oracle公司所收购。

下面简单介绍一下使用ibbackup工具的备份步骤。

(1)编辑用于启动的配置文件my.cnf和用于备份的配置文件backup-my.cnf。

my.cnf的例子如下:

[mysqld]

datadir = /home/heikki/data

innodb_data_home_dir = /home/heikki/data

innodb_data_file_path = ibdata1:100M;ibdata2:200M;ibdata3:500M:autoextend

innodb_log_group_home_dir = /home/heikki/data

set-variable = innodb_log_files_in_group=2

set-variable = innodb_log_file_size=20M

(2)如果想备份到/home/heikki/backup,则backup-my.cnf的例子如下:

[mysqld]

datadir = /home/heikki/backup

innodb_data_home_dir = /home/heikki/backup

innodb_data_file_path = ibdata1:100M;ibdata2:200M;ibdata3:500M:autoextend

innodb_log_group_home_dir = /home/heikki/backup

set-variable = innodb_log_files_in_group=2

set-variable = innodb_log_file_size=20M

(3)开始备份,具体如下:

$ ibbackup /home/pekka/my.cnf /home/pekka/backup-my.cnf

InnoDB Hot Backup version 2.0-beta3; Copyright 2003 Innobase Oy

License A00001 is granted to Innobase Oy

Type ibbackup –license for detailed license terms, –help for help

Contents of /home/pekka/my.cnf:

innodb_data_home_dir got value /home/heikki/data

innodb_data_file_path got value ibdata1:100M;ibdata2:200M;ibdata3: 500M: autoextend

datadir got value /home/heikki/data

innodb_log_group_home_dir got value /home/heikki/data

innodb_log_files_in_group got value 3

innodb_log_file_size got value 10485760

Contents of /home/pekka/backup-my.cnf:

innodb_data_home_dir got value /home/heikki/backup

innodb_data_file_path got value ibdata1:100M;ibdata2:200M;ibdata3:500M: autoextend

datadir got value /home/heikki/backup

innodb_log_group_home_dir got value /home/heikki/backup

innodb_log_files_in_group got value 3

innodb_log_file_size got value 10485760

ibbackup: Found checkpoint at lsn 0 268331310

ibbackup: Starting log scan from lsn 0 268331008

040121 17:35:46 ibbackup: Copying log…

040121 17:35:47 ibbackup: Switching to log file 2, lsn 0 272584704

040121 17:35:49 ibbackup: Log copied, lsn 0 282171935

ibbackup: We wait 10 seconds before starting copying the data files…

040121 17:35:59 ibbackup: Copying /home/heikki/data/ibdata1

040121 17:35:59 ibbackup: Switching to log file 0, lsn 0 283068416

040121 17:36:42 ibbackup: Copying /home/heikki/data/ibdata2

040121 17:38:19 ibbackup: Copying /home/heikki/data/ibdata3

ibbackup: A copied database page was modified at 0 284263243

ibbackup: Scanned log up to lsn 0 291666654

ibbackup: Was able to parse the log up to lsn 0 291666654

ibbackup: Maximum page number for a log record 3127

040121 17:42:15 ibbackup: Full backup completed!

注意:ibbackup 工具不会覆盖任何重名的文件,因此在新的备份开始之前,需要确保备份目录中没有重名文件,否则备份很可能会失败。

(4)备份完成后,备份目录下包含有数据文件和日志文件,如下所示:

$ ls -lh /home/heikki/backup

total 824M

-rw-r—– 1 pekka dev 22M Jan 21 17:42 ibbackup_logfile

-rw-r—– 1 pekka dev 100M Jan 21 17:36 ibdata1

-rw-r—– 1 pekka dev 200M Jan 21 17:38 ibdata2

-rw-r—– 1 pekka dev 500M Jan 21 17:42 ibdata3

因为在cp数据文件时,文件内容在不断地变化,因此在不同时间点cp的数据块中的数据很可能是不一致的。因此,ibbackup在备份期间用一个日志文件ibbackup_logfile记录了备份期间数据的变化,在恢复的时候就可以用此日志文件对备份的数据文件进行日志重做,使得备份的数据能够保持完整性和一致性。

当主数据库出现故障时,我们需要用备份进行恢复,恢复的步骤如下。

进行日志重做。如前面所述,利用下面的命令对备份数据进行日志重做。

shell>ibbackup --apply-log /home/pekka/backup-my.cnf

恢复后重启数据库服务:

shell>./bin/mysqld_saft --defaults-file=/home/pekka/backup-my.cnf &

服务重启后,利用BINLOG日志将备份点与故障点之间的剩余数据进行恢复。

mysqlbinlog binlog-file | mysql -u root –p***

ibbackup还有一些其他的功能,比如压缩备份、不完全恢复等,这里就不再赘述。更详细的使用方法读者可以用“ ibbackup --help”命令进行查看,或者参阅官方帮助文档(http://www.innodb.com/support/documentation/innodb-hot-backup-manual/)。对于 InnoDB 和MyISAM混合的数据库,Innobase公司还提供了一个开源的Perl脚本innobackup,它可以将两种存储引擎的表一起进行备份,具体使用方法读者可以参阅上述链接中的文档。

3.Xtrabackup热备工具

Xtrabackup是Percona公司CTO Vadim参与开发的一款基于 InnoDB的在线热备工具,具有开源、免费、支持在线热备、备份恢复速度快、占用磁盘空间小等特点,并且支持不同情况下的多种备份形式。Xtrabackup的官方下载地址为http://www.percona.com/redir/downloads/XtraBackup

Xtrabackup包含两个主要的工具,即xtrabackup和innobackupex,二者区别如下:

xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表;

innobackupex 是一个封装了 xtrabackup 的 Perl 脚本,支持同时备份 InnoDB 和MyISAM,但在对MyISAM备份时需要加一个全局的读锁。

下面以innobackupex为例,来介绍一下此工具备份、恢复、增量备份恢复的原理。

(1)备份过程。

innobackupex备份过程如图27-1所示。

figure_0463_0194.jpg 图27-1 innobackupex备份过程

在图 27-1中,备份开始时首先会开启一个后台检测进程,实时检测mysql redo的变化,一旦发现 redo 中有新日志写入,立刻将日志记入后台日志文件 xtrabackup_log 中。之后复制InnoDB的数据文件和系统表空间文件 ibdata1,待复制结束后,执行 flush tables with read lock操作,复制.frm、.MYI、.MYD等文件(执行 flush tables with read lock的目的是为了防止数据表发生DDL操作,并且在这一时刻获得 binlog的位置),最后会发出 unlock tables,把表设置为可读写状态,最终停止xtrabackup_log。

(2)全备恢复。

这一阶段会启动XtraBackup内嵌的InnoDB实例,回放xtrabackup日志xtrabackup_log,将提交的事务信息变更应用到 InnoDB 数据/表空间,同时回滚未提交的事务(这一过程类似InnoDB的实例恢复)。恢复过程原理如图27-2所示。

figure_0463_0195.jpg 图27-2 innobackupex恢复过程

(3)增量备份。

innobackupex增量备份过程中的“增量”处理,其实主要是相对InnoDB而言,对MyISAM和其他存储引擎而言,它仍然是一个全拷贝。

“增量”备份的过程主要是通过拷贝InnoDB中有变更的“页”(这些变更的数据页指的是“页”的LSN大于xtrabackup_checkpoints中给定的LSN)。增量备份是基于全备的,第一次增备的数据必须要基于上一次的全备,之后的每次增倍都是基于上一次的增倍,最终达到一致性的增备。

增量备份过程如图27-3所示,和全备过程很类似,区别仅在第②步。

figure_0464_0196.jpg 图27-3 innobackupex增量备份过程

(4)增量备份恢复。

和全备份恢复类似,也需要两步,一是数据文件的恢复,如图 27-4 所示,这里的数据来源由 3部分组成:全备份、增量备份和 xtrabackup log。二是对未提交事务的回滚,如图 27-5所示。

figure_0464_0197.jpg 图27-4 innobackupex增量备份恢复过程1

figure_0465_0198.jpg 图27-5 innobackupex增量备份恢复过程2

4.innobacupex使用示例

下面我们将通过例子向读者详细介绍innobacupex的使用方法。首先从http://www.percona.com下载和安装Percona XtraBackup软件:

wget -c

http://www.percona.com/redir/downloads/XtraBackup/XtraBackup-2.1.2/binary/Linux/x86_6 4/percona-xtrabackup-2.1.2-611.tar.gz

tar xvzf percona-xtrabackup-2.1.2-611.tar.gz

cd percona-xtrabackup-2.1.2

mv percona-xtrabackup-2.1.2 /usr/local/xtrabackup

export PATH=/usr/local/xtrabackup/bin/:$PATH

(1)全量备份。

创建备份用户:

mysql> CREATE USER 'backup'@'%' IDENTIFIED BY '123456';

mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, CREATE TABLESPACE, SUPER ON . TO 'backup'@'%';

规划好备份目录路径为 mkdir -p /data/backup/hotbackup/。创建 innobackupex的配置文件/tmp/my.cnf,如下所示:

[mysqld]

datadir = "/home/mysql_test/mysqlhome/data/"

innodb_data_home_dir = "/home/mysql_test/mysqlhome/data1"

innodb_data_file_path = "ibdata1:10M:autoextend"

innodb_log_group_home_dir = "/home/mysql_test/mysqlhome/data/"

innodb_log_files_in_group = 2

innodb_log_file_size = 536870912

创建测试表:

Mysql>use test;

create table test(id int auto_increment not null primary key,name varchar(20));

insert into test(name) values('test1');

insert into test(name) values('test2');

insert into test(name) values('test3');

insert into test(name) values('test4');

进行全备:

innobackupex --user=backup --password=123456 --socket=/tmp/mysql_test.sock --defaults-file=/tmp/my.cnf /data/backup/hotbackup/full --no-timestamp

恢复全备:

innobackupex --apply-log --use-memory=20G /data/backup/hotbackup/full

恢复备份到MySQL的数据文件目录,这一过程要先关闭MySQL数据库,重命名原数据文件目录,再创建一个新的数据文件目录,将备份数据复制到新的数据文件目录下,赋权,启动MySQL数据库:

mysqladmin -S /tmp/mysql_test.sock shut

mv /home/mysql_test/mysqlhome/data /home/mysql_test/mysqlhome/data_bak

mkdir /home/mysql_test/mysqlhome/data

innobackupex --defaults-file=/tmp/my.cnf --copy-back --rsync /data/backup/hotbackup/full/

chown -R mysql_test:mysql_test /home/mysql_test/mysqlhome/data

cd /home/mysql_test/mysqlhome

./bin/mysqld_safe –user=mysql &

校验恢复后数据库的一致性,查看test数据表:

mysql>use test;

mysql>select * from test;

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

| id | name |

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

| 1 | test1 |

| 2 | test2 |

| 3 | test3 |

| 4 | test4 |

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

4 rows in set (0.00 sec)

可以看到test库下test数据表已经成功恢复。

(2)增量备份。

在MySQL中进行增量备份时,首先要进行一次全量备份,第一次增量备份是基于全备的,之后的增量备份是基于上一次的增量备份。

创建基础备份base:

innobackupex --user=backup --password=123456 --socket=/tmp/mysql_test.sock --defaults-file=/tmp/my.cnf /data/backup/hotbackup/base --no-timestamp

在test库下增加增量数据:

mysql> insert into test(name) values('test5');

Query OK, 1 row affected (0.00 sec)

mysql> insert into test(name) values('test6');

Query OK, 1 row affected (0.00 sec)

mysql> insert into test(name) values('test7');

Query OK, 1 row affected (0.02 sec)

mysql> insert into test(name) values('test8');

Query OK, 1 row affected (0.00 sec)

mysql> select * from test;

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

| id | name |

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

| 1 | test1 |

| 2 | test2 |

| 3 | test3 |

| 4 | test4 |

| 5 | test5 |

| 6 | test6 |

| 7 | test7 |

| 8 | test8 |

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

8 rows in set (0.00 sec)

创建增量备份incremental_one:

Innobackupex --user=backup --password=123456 --socket=/tmp/mysql_test.sock --defaults-file=/tmp/my.cnf --incremental /data/backup/hotbackup/incremental_one --incremental-basedir=/data/backup/hotbackup/base --no-timestamp --parallel=2

在test库下继续插入增量数据:

mysql> insert into test(name) values('test9');

Query OK, 1 row affected (0.00 sec)

mysql> insert into test(name) values('test10');

Query OK, 1 row affected (0.00 sec)

mysql> select * from test;

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

| id | name |

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

| 1 | test1 |

| 2 | test2 |

| 3 | test3 |

| 4 | test4 |

| 5 | test5 |

| 6 | test6 |

| 7 | test7 |

| 8 | test8 |

| 9 | test9 |

| 10 | test10 |

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

10 rows in set (0.00 sec)

创建增量备份incremental_two:

innobackupex --user=backup --password=123456 --socket=/tmp/mysql_test.sock --defaults-file=/tmp/my.cnf --incremental /data/backup/hotbackup/incremental_two --incremental-basedir=/data/backup/hotbackup/incremental_one --no-timestamp --parallel=2

(3)增量备份恢复。

增量备份的恢复大体分为3个步骤:

恢复基础备份(全备);

恢复增量备份到基础备份(开始恢复的增量备份要添加--redo-only参数,到最后一次增量备份去掉--redo-only参数);

对整体的基础备份进行恢复,回滚那些未提交的数据。

恢复基础备份(注意这里一定要加--redo-only参数,该参数的意思是只应用xtrabackup日志中已经提交的事务数据,不回滚还未提交的数据):

innobackupex --apply-log --redo-only --use-memory=20G /data/backup/hotbackup/base

将增量备份incremental_one应用到基础备份base:

innobackupex --apply-log --redo-only --use-memory=20G /data/backup/hotbackup/base--incremental-dir=/data/backup/hotbackup/incremental_one/

将增量备份incremental_two应用到基础备份base(注意恢复最后一个增量备份时需要去掉--redo-only参数,回滚xtrabackup日志中那些还未提交的数据):

innobackupex--apply-log--use-memory=20G/data/backup/hotbackup/base--incremental-dir=/data/backup/hotbackup/incremental_two/

把所有合在一起的基础备份整体进行一次apply操作,回滚未提交的数据:

innobackupex --apply-log --use-memory=20G /data/backup/hotbackup/base

把恢复完的备份复制到数据文件目录中,赋权,然后启动MySQL数据库:

mysqladmin -s /tmp/mysql.sock shut

mv /home/mysql_test/mysqlhome/data /home/mysql_test/mysqlhome/data_bak

mkdir /home/mysql_test/mysqlhome/data

innobackupex --defaults-file=/tmp/my.cnf --copy-back --rsync /data/backup/hotbackup/full/

chown -R mysql_test:mysql_test /home/mysql_test/mysqlhome/data

cd /home/mysql_test/mysqlhome

./bin/mysqld_safe –user=mysql &

查看最终数据:

mysql> select * from test;

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

| id | name |

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

| 1 | test1 |

| 2 | test2 |

| 3 | test3 |

| 4 | test4 |

| 5 | test5 |

| 6 | test6 |

| 7 | test7 |

| 8 | test8 |

| 9 | test9 |

| 10| test10 |

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

10 ows in set (0.00 sec)

(4)不完全恢复。

上文已经详细介绍了如何通过mysqlbinlog进行不完全恢复,mysqlbinlog的不完全恢复的方法同样适合于innobackup热备的不完全恢复。

例如,在2013年6月26日下午14:00的时候开发人员在测试环境上进行了一次误操作, drop掉了一张业务表,这个时候找到DBA,由于库并不是很大,并且为测试库,并没有访问,这个时候我们可以进行基于位置和基于时间点的不完全恢复。

首先我们找到早上的备份:

cd /data/backup/hotbackup/full/20130626

ls –l

total 2361376

-rw-r--r-- 1 root root 262 Jun 26 18:46 backup-my.cnf

-rw-r----- 1 root root 2418016256 Jun 26 18:47 ibdata1

drwxr-xr-x 2 root root 4096 Jun 26 18:47 mysql

drwxr-xr-x 2 root root 4096 Jun 26 18:47 performance_schema

drwxr-xr-x 2 root root 4096 Jun 26 18:47 ps_helper

drwx------ 2 root root 143 Jun 26 18:47 test

-rw-r--r-- 1 root root 13 Jun 26 18:47 xtrabackup_binary

-rw-r--r-- 1 root root 26 Jun 26 18:47 xtrabackup_binlog_info

-rw-r----- 1 root root 97 Jun 26 18:47 xtrabackup_checkpoints

-rw-r----- 1 root root 2560 Jun 26 18:47 xtrabackup_logfile

找到记录备份结束时刻的 binlog 的位置文件 xtrabackup_binlog_info,查看备份结束时刻binlog的名称和位置。

cat xtrabackup_binlog_info

mysql-bin.000001 516847

查看当前数据库的binlog文件和位置:

mysql> show master logs;

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

| Log_name | File_size |

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

| mysql-bin.000001 | 517340 |

| mysql-bin.000002 | 107 |

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

2 rows in set (0.00 sec)

从全备中恢复数据库,恢复全备,之后再从热备结束时刻binlog的位置开始,恢复到误操作时刻14:00之前的binlog。

mysqlbinlog --start-position="516847" --stop-datetime=” 2013-06-26 13:59:59” /home/mysql_test/data/mysql-bin.000001 /home/mysql_test/data/mysql-bin.000002 | mysql -u root –pmypwd

跳过故障点的误操作的时间点,应用之后的所有binlog文件。

Mysqlbinlog --start-datetime="2013-06-26 14:01:00" /home/mysql_test/data/ mysql-bin.000001/home/mysql_test/data/ mysql-bin.000002 | mysql -u root -pmypwd

到此为止,一次基于位置和时间点的不完全恢复完成。

(5)克隆slave。

在日常生活中,我们做得比较多的操作是在线添加从库,比如线上有一主一从两个数据库,由于业务的需要一台从库的读取量无法满足现在的需求,这样就需要我们在线添加从库,出于安全考虑,我们通常需要在从库上进行在线克隆slave。

克隆slave时,常用参数--slave-info和--safe-slave-backup。

--slave-info会将Master的binary log的文件名和偏移位置保存到xtrabackup_slave_info文件中。

--safe-slave-backup则会暂停Slave的SQL线程,直到没有打开的临时表的时候开始备份。待备份结束后SQL线程会自动启动,这样操作的目的主要是确保一致性的复制状态。

下面的例子,将介绍一主一从情况下在线搭建新的从库,环境如下:

Master:192.168.1.1 //主机名为master

Slave:192.168.1.2//主机名为slave

NewSlave:192.168.1.3 //主机名为newslave

在上述案例中,主机名为newslave的主机即为新搭建的从库。在主机名为slave的主机上进行备份:

[root@slave~]#innobackupex --user=backup --password=123456 --socket=/tmp/mysql_test. sock --defaults-file=/tmp/my.cnf --slave-info --safe-slave-backup /data/backup/hotbackup/cloneslave--no-timestamp --parallel=2

查看目录下生成的文件:

[root@slave~]# ls -lrt /data/backup/hotbackup/cloneslave

total 2361380

-rw-r--r-- 1 root root 262 May 29 10:49 backup-my.cnf

-rw-r----- 1 root root 2418016256 May 29 10:50 ibdata1

-rw-r--r-- 1 root root 26 May 29 10:50 xtrabackup_binlog_info

-rw-r--r-- 1 root root 74 May 29 10:50 xtrabackup_slave_info

drwxr-xr-x 2 root root 4096 May 29 10:50 performance_schema

drwxr-xr-x 2 root root4096 May 29 10:50 ps_helper

drwxr-xr-x 2 root root4096 May 29 10:50 mysql

drwx------ 2 root root 143 May 29 10:50 test

-rw-r----- 1 root root 2560 May 29 10:50 xtrabackup_logfile

-rw-r----- 1 root root 97 May 29 10:50 xtrabackup_checkpoints

-rw-r--r-- 1 root root 13 May 29 10:50 xtrabackup_binary

查看 xtrabackup_slave_info文件的内容,这个内容即为搭建从库时刻的 change mater to参数:

[root@slave~]#cat /data/backup/hotbackup/cloneslave/xtrabackup_slave_info

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000044', MASTER_LOG_POS=27399

在主机名为slave的主机上进行还原:

[root@slave~]#innobackupex --apply-log --redo-only --use-memory=20G /data/backup/hotbackup/cloneslave

将还原的文件复制到新的从库newslave上:

[root@slave~]#rsync -avprP -e ssh /data/backup/hotbackup/cloneslave newslave: /home/mysql_test/mysqlhome/data

在主机名为master的主库上添加对主机newslave的授权:

mysql> GRANT REPLICATION SLAVE ON . TO 'repl'@'slave2'

IDENTIFIED BY '123456';

在主机newsalve上拷贝主机为slave的my.cnf文件,并且修改server-id参数,修改完毕后,启动新的从库newslave:

[root@newslave~]# scp slave:/etc/mysql/my.cnf /etc/mysql/my.cnf

skip-slave-start

server-id=3

log-slave-updates=1

查找主机 slave 备份后生成的 xtrabackup_slave_info 文件,提取其中的 master_log_file 和master_log_pos信息,然后在新的从库 newslave上进行 change master to操作。

在newslave上:

mysql> CHANGE MASTER TO

MASTER_HOST='master'

MASTER_USER='repl',

MASTER_PASSWORD='123456',

MASTER_LOG_FILE='mysql-bin.000044',

MASTER_LOG_POS=27399;

启动从库,并且检查复制是否正常:

mysql> START SLAVE;

Slave_IO_Running: Yes

Slave_SQL_Running: Yes