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
下边为二进制日志文件的一段:
事件发生的日期和时间;(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';
如果没有开启,则在配置文件写入:innodb_file_per_table = 1
查看二进制日志的保存名:show master logs;
可以手动配置写如配置文件:log-bin=/mybinlog/mysql-bin #自己指定二进制日志位置,建议二进制日志不要和数据放在同磁盘。此处实验就不做修改,默认和数据目录在一起存放的
查看数据的存放位置: MariaDB [(none)]> show global variables like '%datadir%';
可以手动配置写如配置文件:datadir = /mydata/data/
配置完配置文件重启要mysql.
准备实验数据:
使用test默认测试库;
MariaDB [(none)]> use test
create table tb1 (id int);
insert into tb1(id) values (10),(20);
数据备份存放目录使用/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
查看是否成功:
往数据表中插入一行数据;
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
数据完整还原:
模拟数据误删:磁盘坏掉
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数据。
还原二进制文件
[root@localhost data]# mysql < /backup/binlog-2014-09-02_01\:38\:16.sql
备份后插入的数据回来了!
数据备份方案二: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;
2 rows in set (0.00 sec)
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 ]
恢复二进制文件
[root@node2 data]# mysql < /backup/binlog-2014-09-08-20:11:06.sql
基于快照的备份恢复就完成了。也可以直接复制整个数据目录做所有数据备份。
数据备份方案三: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
配置文件里的大小确实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
查看一下备份的文件:
假设没有增量备份,
要还原备份首先需要准备一下完全备份:
[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!
查看恢复回来的数据的权限,
[root@node2 data]# chown -R mysql.mysql * #将属组属主全改为MySQL
启动MySQL即可。数据也都还原回来了。
那么用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!
生成新的增量备份
再来所以此增量备份。修改数据。
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
mysql数据库的备份还原就写到这里。