MySQL学习——备份和恢复


一、备份类型

1、从备份时,服务器是否关闭的的情况可以分为:

  热备   数据库在线,服务不终止,读写同时进行,基于能实现事务的引擎来实现。

  温备   服务器不关闭,但只能读不能写,保证备份一致性    //先锁表,在备份,最后解锁

  冷备   服务器关闭在备份,一般冷备最安全,不适合任何环境。


2、从备份的方式可以分为

  逻辑备份:

     备份的是DDL和insert语句 ,不包括update和delete,因为只是最终结果的操作语句,所以不需要update和delete,命令重新执行一遍,就可以实现数据库的重建。

     逻辑备份的结果一般是文本存储,可以跨平台,只需修改一些版本信息配置等。

  物理备份:

     直接复制数据文件进行的备份 ,备份速度和恢复速度比逻辑备份快。但是跨平台的能力差。


3、从备份数据的范围,备份分为:

   完全备份:备份所有数据。

   增量备份:从上一次完全备份或增量备份后的数据备份。

   差异备份:每次备份都是从上一次完全备份或增量备份到现在的内容进行备份。



二、备份的内容

   1、二进制日志

   2、InnoDB 的日志文件,就是datadir目录下的ib_logfile0/1)

   3、mysql的主配置文件

   4、从服务器上的master.info

   5、从服务器上的中继日志



三、mysql常用的备份工具

   1、mysqldump  逻辑备份的工具,对innodb热备,对其他引擎温备。

   2、SELECT INTO OUTFILE 可以只备份某个表的某些内容。

   3、ibbackup  物理备份,对innodb热备,对其他引擎温备,速度快。(收费)

   4、filesystem(copy files) 冷备,备份和回复速度快。

   5、基于LVM创建快照,速度快。加读锁-->快照-->解锁



四、备份策略

   1、如果日志内容小,可以直接完全备份。

   2、如果日志内容大,可以完全备份+增量备份。

   3、Binary log 最好不要跟数据文件放在同一磁盘上,要经常备份。

   4、经常测试备份还原。



五、mysqldump

逻辑备份工具,备份出来的是文本文件,ASCII format,可以远程备份。

#mysqldump -uroot -hlocalhost -pPASSWD --all-databases > /backup/alldatabase-'date+%F-%H-%M-%S'.sql

常用选项:  

--all-databases 备份某主机上的所有数据库。
--databases  指定备份哪些数据库
   备份某一个数据库的某一个表,直接指定即可,如果有多张表,用空格隔开。备份之前要先锁定表,如果只备份单个表,可以使用--lock-tables进行锁定,例如:
     #mysqldump db1 tb1 --lock-tables > /backup/tb1.sql
   支持事务的存储引擎,可以热备,否则需要加锁
--lock-all-tables 锁定所有表,备份完自动释放
--locak-tables 锁定一个表,同时备份过个表用空格隔开,备份前先锁定.
--flush-logs 让二进制日志滚动一下,开启一个新文件,如果以后做时间点恢复,只需要新的二进制日志文件即可。
--no-data  只备份DDL语句,不备份数据(不要使用)
--master-data=n 在备份时同时导出二进制文件的文件名和位置(便于找到二进制文件的点,即记录日志位置)。一般加上--master-data=2.
    n=1|2  (一般使用2,保存为注释了的CHANGE MASTER文件,1为不注释)
--replace  都保存为replace语句
--events 备份事件
--routines 备份存储过程和存储函数
--triggers  备份触发器
--single-transaction    让InnoDB的表实现热备功能,不需要锁定表,其他的写操作一样能进行,如果是InnoDB实现热备,一定要加该选项。


还原数据时的内容不用记录在二进制日志里面,所以最好先关闭二进制日志在还原,还原后,在启用二进制日志。



六、备份和恢复的具体实现

1、温备实现

对数据库db1进行备份,假设db1使用非事务引擎。db1中有表tb1,内容如下:

mysql> use db1
Database changed
mysql> select * from tb1;
+------+------+
| id   | name |
+------+------+
|    1 | jim  |
|    2 | tom  |
+------+------+

这里有两种备份方法,第一中在mysql中加锁备份,第二种在命令行中直接加锁备份

方法一:

1、先加读锁:  

mysql> use db1;
Database changed
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.02 sec)

2、对数据库进行备份:

[root@localhost ~]# mysqldump --databases db1 > /root/db1-`date +%F-%H-%M-%S`.sql

3、备份之后要对数据库解锁:

mysql> use db1;
Database changed
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)


方法二:

mysqldump --databases db1 --lock-all-tables >/root/db1-`date +%F-%H-%M-%S`.sql


可以查看备份的sql文件:

[root@localhost ~]# ls | grep sql
db1-2013-06-09-16-49-58.sql
db1-2013-06-09-16-54-26.sql


恢复数据库

假设数据库db1丢失,即删除数据库db1

mysql> drop database db1;
Query OK, 1 row affected (0.08 sec)
mysql> use db1
ERROR 1049 (42000): Unknown database 'db1'

恢复数据库db1:

[root@localhost ~]# mysql < db1-2013-06-09-16-54-26.sql

查看是否恢复

mysql> use db1
ERROR 1049 (42000): Unknown database 'db1'
mysql> use db1;
Database changed
mysql> show tables;
+---------------+
| Tables_in_db1 |
+---------------+
| tb1           |
+---------------+
1 row in set (0.00 sec)
mysql> select * from tb1;
+------+------+
| id   | name |
+------+------+
|    1 | jim  |
|    2 | tom  |
+------+------+
2 rows in set (0.00 sec)

说明数据库已经恢复。

//如果只是删除了数据库db1中tb1表,要恢复tb1时:#mysql db1 < tb1.sql



二、SELECT INTO OUTFILE进行备份和还

这种方法可根据自己的需要只对表中的符合某些条件的数据进行备份,备份保存的直接是数据内容,而不是命令语句。

SELECT  *  INTO OUTFILE  ’/tmp/t1.txt’  FROM t1 [WHERE]; 将某些数据内容保存到/tmp/t1.txt文件里,/tmp/t1.txt文件的属主和属组必须是mysql。

例如:

mysql> lock tables tb1 lock;    //先锁定表tb1
mysql> select * into outfile '/mysql/data/a.txt' from tb1 where name='tom';
Query OK, 1 row affected (0.00 sec)
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)


可一看一下a.txt中的内容:

[root@localhost ~]# cat /mysql/data/a.txt
2   tom
[root@localhost ~]# ll /mysql/data/a.txt
-rw-rw-rw- 1 mysql mysql 6 06-09 17:28 /mysql/data/a.txt


/mysql/data/a.txt内容不能使用‘<’的方式导入,因为不是命令语句,导入方式:

mysql> CREATE TABLE tb2 LIKE tb1;
Query OK, 0 rows affected (0.02 sec)
mysql> lock table tb2 write;
Query OK, 0 rows affected (0.00 sec)
mysql> load data infile '/mysql/data/a.txt' into table tb2;
Query OK, 1 row affected (0.04 sec)
Records: 1  Deleted: 0  Skipped: 0  Warnings: 0
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tb2;
+------+------+
| id   | name |
+------+------+
|    2 | tom  |
+------+------+
1 row in set (0.00 sec)



三、通过完全备份和二进制日志备份,实现即时点恢复

假设此时使用的是InnoDB引擎,可以实现热备,不需要锁表。

1、先进行完全备份:

[root@localhost ~]# mysqldump --databases db1 --single-transaction --flush-logs --master-data=2 > /root/db1-`date +%F-%H-%M-%S`.sql
************************************************************
//实时可以查看滚动到新的二进制日志文件的名字和位置
[root@localhost ~]# cat db1-2013-06-09-17-45-30.sql | grep 'CHANGE MASTE'
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000008', MASTER_LOG_POS=107;
//此时新的二进制日志文件为mysql-bin.000008,起始位置为MASTER_LOG_POS=107;


2、模拟完全备份之后对数据库进行一些操作,使数据库改变:

mysql> use db1;
Database changed
mysql> insert into tb1 values (3,'jack'),(4,'jam');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> select * from tb1;
+------+------+
| id   | name |
+------+------+
|    1 | jim  |
|    2 | tom  |
|    3 | jack |
|    4 | jam  |
+------+------+
4 rows in set (0.00 sec)


3、查看新的二进制日志,确定需要恢复到的结束点:

[root@localhost ~]# mysqlbinlog /mysql/data/mysql-bin.000008 | tail
SET TIMESTAMP=1370772530/*!*/;
insert into tb1 values (3,'jack'),(4,'jam')
/*!*/;
# at 279
#130609 18:08:50 server id 1  end_log_pos 306   Xid = 233
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

   假设在“end_log_pos 306”,即306之前的数据我们都需要恢复。

4、备份二进制日志

[root@localhost ~]# mysqlbinlog /mysql/data/mysql-bin.000008 --stop-position=306 > /root/bin.log

5、数据恢复。假设此时数据库db1损坏了,需要进行恢复,恢复时最好关掉二进制日志,恢复过程不需要记录.

mysql> drop database db1;
Query OK, 2 rows affected (0.05 sec)
mysql> set SQL_LOG_BIN=0;   //关闭二进制日志
Query OK, 0 rows affected (0.00 sec)
mysql> show databases;    //此时已经没有db1了
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
mysql> source /root/db1-2013-06-09-17-45-30.sql    //完全恢复
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
......
mysql> source /root/bin.log    //二进制日志内容恢复
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
......
mysql> set SQL_LOG_BIN=1;    //打开二进制日志
Query OK, 0 rows affected (0.00 sec)
mysql> show databases;    //db1已经恢复
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)
mysql> use db1
Database changed
mysql> select * from tb1;    //tb1已经恢复,且有jack和jam
+------+------+
| id   | name |
+------+------+
|    1 | jim  |
|    2 | tom  |
|    3 | jack |
|    4 | jam  |
+------+------+
4 rows in set (0.00 sec)




四、基于文件系统的物理备份

这种方法只能实现冷备

   #service mysqld stop

   #cd /mysql/data/

   #cp -rp ./* /back/data/          // -p 保持原属性

   数据库出错时再将数据复制回/mysql/data,改变属主属组为mysql即可

   #service mysqld start



五、基于快照卷的物理备份

此时需要创建逻辑卷作为mysql的datadir,假设服务器上的dadadir目录"/mysql/data"挂载在逻辑卷"/dev/vg/lv"上

mysql> FLUSH TABLES WITH READ LOCK;    //给表加读锁
mysql> SHOW MASTER STATUS\G  或 mysql> FLUSH LOGS ;//记录二进制日志位置
# lvcreate -L 50M -n data-snap -s -p r /dev/myvg/mydata //创建快照data-snap
mysql> UNLOCK TABLES;    //解锁
# mkdir /snap    //创建挂载快照的目录
# mount -r /dev/vg/data-snap /snap      //-r只读挂载
# tar jcf all_data-20130629.tar.bz2 /snap/*    //将快照文件打包
# umount /snap    //卸载快照  
# lvremove /dev/vg/data-snap        //删除快照
***********************************************************
数据库出错时还原:(还原所有库的表要关闭服务器)
1、先复制二进制日志文件(一般二进制日志不要存放在datadir目录,此步骤可省略)
#service mysqld stop
# cd /mysql/data/
# cp mysql-bin.000007 /tmp  //将二进制日志文件复制走,此二进制文件即为flush logs后最新的二进制日志(此时的二进制日志里记录了从创建快照到当前时刻的数据改变内容)
2、模拟数据库出现损坏
# cd..
# rm -rf data/
3、数据恢复
# tar xf /tmp/all_data-20130629.tar.bz2 -C ./
#service mysqld start
#mysqlbinlog /tmp/mysql-bin.000007   //查看二进制文件内容
#mysqlbinlog /tmp/mysql-bin.000007 --stop-position=306  > /tmp/db.sql   //将从创建快照到306时刻的二进制日志导入到/tmp/db.sql里
然后在mysql里加载/tmp/db.sql文件:
mysql>SET SQL_LOG_BIN=0   //关闭二进制文件功能
mysql>SOURCE /tmp/db.sql  //导如二进制日志,做增量恢复
mysql>SET SQL_LOG_BIN=1   //开启二进制日志



六、使用percona组织的xtrabackup来实现mysql的备份

   由于此功能比较强大,篇幅较大,以后单独介绍。