MySQL的备份和恢复:

为什么要对数据做备份?   

    数据备份主要是用于灾难恢复和测试要求,灾难恢复指硬件故障,软件故障,自然灾害,******以及误操作;

备份分为以下几类:

    完全备份:既对所有数据做备份

    部分备份:仅对数据库中一张或多张表做备份

    差异备份:备份上次备份后变化的数据部分,和增量备份区别在于差异备份只可以相对完全备份做备份

    增量备份:仅备份上次完全备份或增量备份之后变化的数据部分

    热备份:在线备份,读写操作不受影响

    温备份:在线备份,读操作继续,但写操作不允许;

    冷备份:离线备份,数据库服务器离线, 期间不能为业务提供读写服务;

    物理备份:直接复制数据文件进行的备份;好处是基于文件备份。容易跨平台,备份工具简单,copy,tar就可以。

    逻辑备份:从数据库中“导出”数据另存而进行的备份;与存储引擎无关,易于实现,mysqldump,mydumper,phpAdmin都可以实现

注:MyISAM支持到温备份,InnoDB支持热备

备份到底备份的是什么?

备份的是数据,额外的数据(二进制日志和InnoDB的事务日志),代码(存储过程和函数,触发器,事件调度器等),以及服务器配置文件。

备份工具:

cp ,tar等文件系统工具:物理备份工具,使用与所有存储引擎;一般用于MyISAM,支持冷备,完全备份和部分备份

    mysqldump:逻辑备份工具,适用于所有存储引擎,温备,完全备份,部分备份;不支持增量备份。且只对InnoDB支持热备。

    lvm2的快照:几乎热备;创建快照的时候需要锁定数据库,借助于文件系统工具实现物理备份。

    mysqlhotcopy:物理备份,几乎冷备。仅使用与MyISAM.这里我们只做了解。

    ibbackup:InnoDB,热备份

    xtrebackup:对于InnoDB支持热备,支持完全备份和增量备份,对于MyISAM支持温备,支持完全备份。

基于以上的工具作用,有一下三种备份方案: 

1,mysqldump+binlog:mysqldump做完全备份,通过备份二进制日志备份实现增量备份

2, lvm2快照+binlog:几乎热备,物理备份,完全备份。通过备份二进制日志备份实现增量备份

3,xtrabackup:对InnoDB完全意义的热备,支持完全备份增量备份,两者都是物理备份。速度快。对其他(MyISAM)存储引擎温备,没有增量备份,只支持完全备份    

这里略微提一下二进制日志文件:

二进制日志文件的构成:

        日志文件:文件名前缀.文件名后缀

        索引文件:文件名前缀.index

下边为二进制日志文件的一段:

clipboard

事件发生的日期和时间;(140815 7:00:51)

事件发生在服务器的标识(server id)

事件的结束位置:(end_log_pos 1084684)

事件的类型:(Query)

事件发生时所在的服务器执行此事件的线程的ID:(thread_id=8)

语句的时间戳与将其写入二进制文件中的时间差:(exec_time=170)

错误代码:(error_code=0)  
事件内容:(SET TIMESTAMP=1408057251/*!*/;    
GRANT SELECT ON tdb.* TO
tuser@localhost

二进制日志的查看命令:

mysqlbinlog

    -j, --start-position=#:从指定的事件位置查看

    --stop-position=#:只显示到指定的事件位置

    --start-datetime=name

    --stop-datetime=name

实验环境:

数据库版本为10.0.12-MariaDB

xtrebackup版本:xtrabackup-2.2.3

系统版本CentOS6



准备配置文件:

首先要确保表的独立空间是开启的:show global variables like 'innodb_file_per_table';


clipboard[1]

如果没有开启,则在配置文件写入:innodb_file_per_table = 1

查看二进制日志的保存名:show master logs;

可以手动配置写如配置文件:log-bin=/mybinlog/mysql-bin   #自己指定二进制日志位置,建议二进制日志不要和数据放在同磁盘。此处实验就不做修改,默认和数据目录在一起存放的

clipboard[2]

查看数据的存放位置: MariaDB [(none)]> show global variables like '%datadir%';

可以手动配置写如配置文件:datadir = /mydata/data/

clipboard[3]

配置完配置文件重启要mysql.

准备实验数据:

使用test默认测试库;

MariaDB [(none)]> use test   

create table tb1 (id int);

insert into tb1(id) values (10),(20);

clipboard[4]

数据备份存放目录使用/backup/   若无此目录自行创建

   

数据备份方案一:mysqldump +binlog

mysqldump的用法:

mysqldump:客户端,通过mysql协议链接至mysqld;

        参数:

                -A,--all-databases            所有数据

                -x,--lock-all-tables              锁定所有表   MyISAM和InnoDB都使用,温备方式

                -l, --lock-tables                  锁定备份的表    只有备份单张表时才建议使用                               

                -B,--databases                   备份单个数据库

                -C,--compress                    压缩传输

                InnoDB:--single-transaction      启动一个大的单一事务实现备份。

                -E, --events:备份指定库的事件调度器;

                -R, --routines:备份存储过程和存储函数;

                --triggers:备份触发器

                --master-data[=#]:

                    1:记录CHANGE MASTER TO语句;此语句未被注释;

                    2:记录为注释语句;

               -F,--flush-logs, :锁定表之后执行flush logs命令;

mysqldump完全备份:

[root@www~]# mysqldump --all-databases --lock-all-tables --routines --triggers --master-data=2 --flush-logs > /backup/`date +%F_%T`all.sql

查看是否成功:

clipboard[5]

往数据表中插入一行数据;

MariaDB [test]> insert into tb1(id) values (30);

备份二进制日志文件

[root@www~]# mysqlbinlog --start-datetime '2014-08-15 13:16:33' --stop-datetime '2014-08-15 13:32:52' /mydata/data/mysql-bin.* > /backup/binlog-`date +%F_%T`.sql

clipboard[6]

数据完整还原:

模拟数据误删:磁盘坏掉 


rm -rf /mydata/data/*

初始化mysql并启动:

[root@www ~]# cd /usr/local/mysql/
[root@www mysql]# scripts/mysql_install_db --user=mysql --datadir=/mydata/data/
rm /mydata/data/*                  #下边产生了所悟日志,我们不需要,删除
[root@www ~]# service mysqld start           #启动mysql

还原完全备份数据

[root@localhost data]# mysql < /backup/2014-09-02_01\:04\:05all.sql

查看tb1中的数据,可以看出,没有备份后插入的30数据。

clipboard[7]

还原二进制文件

[root@localhost data]# mysql < /backup/binlog-2014-09-02_01\:38\:16.sql

备份后插入的数据回来了!

clipboard[8]

数据备份方案二:lvm2快照+binlog

1,首先准备一个逻辑逻辑分区。

[root@localhost ~]# fdisk /dev/sdb
命令(输入 m 获取帮助):n
Select (default p): p
分区号 (3,4,默认 3):3
起始 扇区 (20973568-41943039,默认为 20973568):
将使用默认值 20973568
Last 扇区, +扇区 or +size{K,M,G} (20973568-41943039,默认为 41943039):+2G
分区 3 已设置为 Linux 类型,大小设为 2 GiB
命令(输入 m 获取帮助):p
   设备 Boot Start End Blocks Id System
/dev/sdb1 2048 10487807 5242880 83 Linux
/dev/sdb2 10487808 20973567 5242880 83 Linux
/dev/sdb3 20973568 25167871 2097152 83 Linux
命令(输入 m 获取帮助):t
分区号 (1-3,默认 3):3
Hex 代码(输入 L 列出所有代码):8e
已将分区“Linux”的类型更改为“Linux LVM”
命令(输入 m 获取帮助):w
[root@localhost ~]# kpartx -af /dev/sdb                #同步至内核
[root@localhost ~]#partx -a /dev/sdb

2,下来创建LVM。

[root@localhost ~]# pvcreate /dev/sdb3    Physical volume "/dev/sdb3" successfully created    
[root@localhost ~]# vgcreate myvg2 /dev/sdb3    Volume group "myvg2" successfully created
[root@localhost ~]# lvcreate -L 1.5G -n mydata2 myvg2                  Logical volume "mydata2" created    
[root@localhost ~]# mke2fs -t ext4 /dev/myvg2/mydata2                 #格式化    
[root@localhost ~]# mount /dev/myvg2/mydata2 /mydata/data/       #将LVM分区挂载在MySQL的数据目录下上。

3,初始化MySQL数据库。否则挂载的LVM后数据目录下的文件全被隐藏,不初始化MySQL将没有数据库了。

[root@localhost data]# cd /usr/local/mysql/    
[root@localhost mysql]# ls    
bin data INSTALL-BINARY mysql-test share    COPYING docs lib README sql-bench    COPYING.LESSER include man scripts support-files    
[root@localhost mysql]# scripts/mysql_install_db --user=mysql --datadir=/mydata/data/
[root@localhost mysql]# ls /mydata/data/                                 #查看数据目录是否初始化成功    
aria_log.00000001 lost+found mysql-bin.000001 mysql-bin.index test    aria_log_control mysql mysql-bin.000002 performance_schema    
[root@localhost mysql]# service mysqld start                             #启动mysql    Starting MySQL SUCCESS!
[root@localhost mysql]# mysql -uroot -p                    #登陆MySQL
mysql> create database aolens;
mysql> use aolens
Database changed
mysql> show tables;
Empty set (0.00 sec)
mysql> create table tb1 (id int);                #创建表
Query OK, 0 rows affected (0.22 sec)
mysql> insert into tb1(id) values (10),(20);   #添加数据
Query OK, 2 rows affected (0.03 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [aolens]> select * from tb1;

clipboard[9]

2 rows in set (0.00 sec)

clipboard[10]

4,开始备份数据库:

mysql> flush tables with read lock;          #对数据库施加锁
Query OK, 0 rows affected (0.01 sec)
mysql> flush master logs;                     #滚动一下二进制日志。一般与做增量备份
且千万不要退出,已退出就释放锁了。所以另起一个ssh
[root@node2 ~]# lvcreate -L 200M -n mydata-snap /dev/myvg2/mydata2 -s -p r     #创建快照,只读,快照名为mydata-snap    Logical volume "mydata-snap" created
mysql> unlock tables;                             #释放锁
Query OK, 0 rows affected (0.00 sec)
下边我们就可以从容的备份文件了!
[root@node2 ~]# mkdir /snap
[root@node2 ~]# mount /dev/myvg2/mydata-snap /snap/         #挂载快照到/snap/下    mount: block device /dev/mapper/myvg2-mydata--snap is write-protected, mounting read-only
[root@node2 ~]# cd /snap/
[root@node2 snap]# rsync -a aolens /backup/aolens-`date +%F-%T`     #删除快照:
[root@node2 ~]# lvremove /dev/myvg2/mydata-snap
[root@node2 ~]# insert into tb1(id) values (30);

5,备份二进制日志文件


[root@www~]# mysqlbinlog  /mydata/data/mysql-bin.000004 > /backup/binlog-`date +%F_%T`.sql    备份二进制增量。

6,还原数据:

先将aolens数据文件目录删除,

[root@node2 data]# service mysqld stop     #mysql数据库出现问题首先要停掉数据库。    Stopping mysqld:                 [ OK ]
[root@node2 data]# cp -a /backup/aolens-2014-09-08-20\:11\:06/* /mydata/data/        #恢复数据
[root@node2 data]# service mysqld start                                         #启动MySQL    Starting mysqld:                                               [ OK ]

clipboard[11]

恢复二进制文件

[root@node2 data]#  mysql < /backup/binlog-2014-09-08-20:11:06.sql

clipboard[12]

基于快照的备份恢复就完成了。也可以直接复制整个数据目录做所有数据备份。


数据备份方案三:xtrabackup

xtrabackup是由percona提供的,下载地址是:http://www.percona.com/

[root@node2 ~]# yum install percona-xtrabackup

使用的工具就是:innobackupex:客户端工具, 以mysql协议连入mysqld,不支持离线备份

简单说明xtrabackup

1、完全备份

# innobackupex --user=DBUSER --password=DBUSERPASS /path/to/BACKUP-DIR/

如果要使用一个最小权限的用户进行备份,则可基于如下命令创建此类用户:

mysql> CREATE USER ’bkpuser’@’localhost’ IDENTIFIED BY ’s3cret’;
mysql> REVOKE ALL PRIVILEGES, GRANT OPTION FROM ’bkpuser’;
mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO ’bkpuser’@’localhost’;
mysql> FLUSH PRIVILEGES;

第一次在备份

[root@node2 ~]# innobackupex --user=root --password=aolens /backup/
InnoDB: Error: log file ./ib_logfile0 is of different size 5242880 bytes
InnoDB: than specified in the .cnf file 50331648 bytes!
innobackupex: Error: The xtrabackup child process has died at /usr/bin/innobackupex line 2672.

查看发现日志的大小为5M

clipboard[13]

配置文件里的大小确实64M

[root@node2 ~]# cat /etc/my.cnf|grep "innodb_log_file"             
#innodb_log_file_size = 64M

修改配置文件

innodb_log_file_size =5M

重启MySQL

[root@node2 ~]# innobackupex  --user=root --password=aolens /backup/          
innobackupex: Backup created in directory '/backup/2014-09-09_01-05-21'
innobackupex: MySQL binlog position: filename 'mysql-bin.000004', position 245
140909 01:05:24 innobackupex: Connection to database server closed
140909 01:05:24 innobackupex: completed OK!

备份OK

查看一下备份的文件:

clipboard[14]

假设没有增量备份,

要还原备份首先需要准备一下完全备份:

[root@node2 ~]# innobackupex --apply-log /backup/2014-09-09_01-05-21/         #提交未提交的数据
InnoDB: FTS optimize thread exiting.
InnoDB: Starting shutdown...
InnoDB: Shutdown completed; log sequence number 1602582
140909 02:50:01 innobackupex: completed OK!

innobackup不支持离线备份,但是恢复无需启动MySQL。

删除数据目录下的一个库目录。执行恢复。

[root@node2 data]# innobackupex --copy-back /backup/2014-09-09_01-05-21/
innobackupex: Error: Original data directory '/mydata/data' is not empty! at /usr/bin/innobackupex line 2163.    #报错数据目录不为空!
[root@node2 data]# rm -rf *            #删除数据目录下的所有文件。
[root@node2 data]# innobackupex --copy-back /backup/2014-09-09_01-05-21/
innobackupex: Finished copying back files.
140909 02:58:36 innobackupex: completed OK!

clipboard[15]

查看恢复回来的数据的权限,

clipboard[16]    
[
root@node2 data]# chown -R mysql.mysql *                #将属组属主全改为MySQL

启动MySQL即可。数据也都还原回来了。

clipboard[17]

那么用innobackup怎么实现增量备份呢?

每个InnoDB的页面都会包含一个LSN信息,每当相关的数据发生改变,相关的页面的LSN就会自动增长。这正是InnoDB表可以进行增量备份的基础,即innobackupex通过备份上次完全备份之后发生改变的页面来实现。

要实现第一次增量备份,可以使用下面的命令进行:

# innobackupex --incremental /backup --incremental-basedir=BASEDIR

其中,BASEDIR指的是完全备份所在的目录,此命令执行结束后,innobackupex命令会在/backup目录中创建一个新的以时间命名的目录以存放所有的增量备份数据。另外,在执行过增量备份之后再一次进行增量备份时,其--incremental-basedir应该指向上一次的增量备份所在的目录。

需要注意的是,增量备份仅能应用于InnoDB或XtraDB表,对于MyISAM表而言,执行增量备份时其实进行的是完全备份。

我们对数据库的数据做一下修改。插入一个表和数据。做增量备份。

MariaDB [aolens]> create table tb2(id int);
MariaDB [aolens]> insert into tb2(id) values(111),(222);
[root@node2 ~]# innobackupex --incremental /backup/ --incremental-basedir=/backup/2014-09-09_01-05-21/       #相对于完全备份做增量备份。
140909 03:49:46 innobackupex: Connection to database server closed
140909 03:49:46 innobackupex: completed OK!

生成新的增量备份

clipboard[18]

再来所以此增量备份。修改数据。

MariaDB [(none)]> use aolens;
Database changed
MariaDB [aolens]> create table tb3(id int);
Query OK, 0 rows affected (0.01 sec)
MariaDB [aolens]> insert into tb3(id) values(888);
Query OK, 1 row affected (0.05 sec)
[root@node2 ~]# innobackupex --incremental /backup/ --incremental-basedir=/backup/2014-09-09_03-49-40/  #这一次增量式相对于上次增量做增量备份。
140909 04:00:11 innobackupex: Connection to database server closed
140909 04:00:11 innobackupex: completed OK!

“准备”(prepare)增量备份与整理完全备份有着一些不同,尤其要注意的是:

(1)需要在每个备份(包括完全和各个增量备份)上,将已经提交的事务进行“重放”。“重放”之后,所有的备份数据将合并到完全备份上。

(2)基于所有的备份将未提交的事务进行“回滚”。

于是,操作就变成了:

# innobackupex --apply-log --redo-only BASE-DIR

接着执行:

# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-1

而后是第二个增量:

# innobackupex --apply-log --redo-only BASE-DIR --incremental-dir=INCREMENTAL-DIR-2

其中BASE-DIR指的是完全备份所在的目录,而INCREMENTAL-DIR-1指的是第一次增量备份的目录,INCREMENTAL-DIR-2指的是第二次增量备份的目录,其它依次类推,即如果有多次增量备份,每一次都要执行如上操作;

要记住二进制日志一定要分开存放。

停止MySQL

[root@node2 data]# rm -rf *        #删除数据目录下的文件,模拟数据目录坏掉、记住要将二级制分开存放。          
[root@node2 data]# innobackupex --apply-log redo-only /backup/2014-09-09_04-10-25/     #准备完全备份,只提交未提交的。不回滚。
[root@node2 data]# innobackupex --apply-log --redo-only /backup/2014-09-09_01-05-21/ --incremental-dir=/backup/2014-09-09_03-49-40/   #准备第一个增量备份。
innobackupex: Copying '/backup/2014-09-09_03-49-40/aolens/tb2.frm' to '/backup/2014-09-09_01-05-21/aolens/tb2.frm'
140909 04:18:17 innobackupex: completed OK!
[root@node2 data]# innobackupex --apply-log --redo-only /backup/2014-09-09_01-05-21/ --incremental-dir=/backup/2014-09-09_04-00-08/  #合并第二个增量
innobackupex: Copying '/backup/2014-09-09_04-00-08/aolens/tb2.frm' to '/backup/2014-09-09_01-05-21/aolens/tb2.frm'
140909 04:20:36 innobackupex: completed OK!

还原准备好的数据。也就是完全备份

[root@node2 data]# innobackupex --copy-back /backup/2014-09-09_01-05-21/
innobackupex: Finished copying back files.
140909 04:24:21 innobackupex: completed OK!
进入到数据目录下
[root@node2 data]# chown -R mysql.mysql *            #修改回复回来数据的属组属主。
service mysqld start

clipboard[19]

mysql数据库的备份还原就写到这里。