Fork me on GitHub
Fork me on GitHub

基于mysqldump做备份恢复

备份和恢复概念

备份和恢复的意义

  • 灾难恢复:比如机房被淹。
  • 审计:比如想知道某一数据在某一时刻是什么样的。
  • 测试

备份:目的用于恢复。请注意要对备份数据做恢复测试,防止备份的不能恢复,到时候就麻烦了。

备份类型

1.根据备份时,数据库服务器是否在线:

  • 冷备:cold backup。服务器离线,数据库读写操作都不能执行。
  • 温备:warm backup。全局施加共享锁,所有业务只能读,不能写。
  • 热备:hot backup。服务器不离线,读写操作都能进行。这就可能会有问题了。我们去备份,数据量很大,我们得夜间备份,在你复制的过程中,如果文件发生了改变,前一半后一半时间戳不一致,备份好的文件恢复过来是不允许访问的。在文件系统上,这样的文件属于时间点不一致文件,因此是不允许访问的。我们可以把整个数据库锁定,然后创建一快照,通过快照进行备份。通过快照备份,时间点一定是一致的,但是也有一些其他的问题。首先你要锁定整个库,你一锁定,别人就读写不了了。所以这也不能算是热备。真正的热备是指任何业务不终止,它能够自动在背后进行备份,而且自动保证时间点是一致的。【注意】:要想完成热备,通常是基于事务的存储引擎才能完成的。

2.根据备份的数据集:

  • 完全备份:full backup
  • 部分备份: partial backup

3.根据备份时的接口(直接备份数据文件还是通过mysql服务器导出数据):

  • 物理备份:直接复制(归档)数据文件的备份方式;physical backup。
    copy命令就可以备份了,还可以tar归档压缩备份,因此不需要额外的工具就可以备份。恢复也很简单,把备份的文件复制到数据库里面就可以了,但是要兼容才行。但好在MySQL的InnoDB和MyISAM非常容易跨平台,一般来说,在windows上备份的在Linux上也能用,在Linux上备份的在windows上也能用。物理备份比较适合大数据量备份,比如超过10G,甚至几十个G,千万别用逻辑备份。
  • 逻辑备份:把数据从库中提出出来保存为文本文件;logical backup。
    从根本上来讲,逻辑备份备份后为文本文件,我们可以使用grep、sed、awk来处理查看,物理备份的文件则不能被如此处理。而且逻辑备份恢复简单,导入就可以了。逻辑备份也有缺点,比如说与物理备份恢复速度比,逻辑备份恢复更慢,占据空间更大。还有逻辑备份有个重要缺点,无法保证浮点数的精度,因为我们必须把二进制数据转换成文本格式。更重要的是使用逻辑备份还原数据以后还需要重建索引。 对于非常大的表,重建索引是相当消耗时间和资源的,由其是CPU资源。逻辑备份的工具:mysqldump

4.根据备份时是备份整个数据还是仅备份变化的数据:

  • 完全备份:full backup
  • 增量备份:incremental backup。得使用专业的备份工具进行增量备份。
  • 差异备份:differential backup
    增量和差异:差异,每一次起始点不是上一次备份,而是上一次完全备份。见下图。将来设计备份策略的时候,需要根据你的数据量变化频度来设计。

备份策略

  • 选择备份方式
  • 选择备份时间
  • 考虑到恢复成本
    • 恢复时长
  • 备份成本:
    • 锁时间
    • 备份时长
    • 备份负载

备份对象

  • 数据
  • 配置文件
  • 代码:存储过程,存储函数,触发器
  • OS相关的配置文件,如crontab配置计划及相关的脚本

备份工具

1.mysqldump:MySQL原生自带的逻辑备份工具,单线程工具。

  • InnoDB热备、温备和冷备,MyISAM温备,Aria温备
  • 因为是逻辑备份,所以备份和恢复过程较慢

2.mysqldumper: 多线程的mysqldump。装上percona的tools之后,mysqldumper就在里面。多线程同时备份多个库,在必要的场景下缩短备份时间是很有必要的。

这两个备份工具很难实现差异或增量备份;

3.lvm-snapshot: 基于lvm的逻辑卷快照进行备份。

  • 这是接近于热备的工具:为什么叫接近于?因为要先请求全局锁,而后创建快照,并在创建快照完成后释放全局锁;
  • 使用cp、tar等工具进行物理备份;
  • 备份和恢复速度较快;

很难实现增量备份,并且请求全局需要等待一段时间,在繁忙的服务器上尤其如此;

4.部分备份工具:

SELECT clause INTO OUTFILE '/path/to/somefile'
LOAD DATA INFILE '/path/from/somefile'   #恢复时得使用这个命令恢复。
  • 部分备份工具, 不会备份关系定义,仅备份表中的数据;
  • 也是个逻辑备份工具,快于mysqldump。

5.mysqlhotcopy:几乎冷备。

6.专业备份工具:

  • Innobase: 商业备份工具, innobackup
  • Xtrabackup: 由Percona提供的开源备份工具。需要单独安装。
    • InnoDB热备,增量备份;
    • MyISAM温备,只是完全备份,不支持增量;
    • 物理备份,速度快;

mysqldump备份

mysqldump备份介绍

【注意】:数据量在10G以下。
相当于一个MySQL客户端工具,你的服务器在远程,mysqldump在本地,没有任何问题,也就意味着二者可以在不同的主机上。可实现完全备份和部分备份,但是还原一个库时,这个库得事先存在,就是说在还原前,先得CREATE DATABASE。

man mysqldump
mysqldump [options] [db_name [tbl_name ...]]

备份单个库:

mysqldump [options] db_name

恢复时:如果目标库不存在,需要事先手动创建。

【示例1】:备份和恢复。
1.先备份库

[root@db ~]# mysqldump -uroot -hlocalhost -p hellodb >/tmp/hdb.sql
Enter password: 

2.连接上mysql数据库,删除库hellodb

mysql> DROP DATABASE hellodb;
Query OK, 7 rows affected (0.01 sec)

3.恢复,得事先创建库

[root@db ~]# mysql -uroot -hlocalhost -p </tmp/hdb.sql 
Enter password: 
ERROR 1046 (3D000) at line 22: No database selected

mysql> CREATE DATABASE hellodb DEFAULT CHARSET 'utf8';
Query OK, 1 row affected (0.00 sec)

[root@db ~]# mysql -uroot -hlocalhost -p hellodb </tmp/hdb.sql     
Enter password: 

所以说指定数据库进行备份的这种方式,它只是备份这个库里的东西,它以为这个库是事先存在的,所以恢复时是不会自动创建库的。也可以备份某个表。

--all-databases: 备份所有库。恢复时不需要事先创建库名。
--databases db1 db2 ...: 备份指定的多个库。多个库名间用空格隔开,事先不需要创建库名。

【示例2】:备份前加锁。(这才是真正的备份,要锁表)

  • –lock-all-tables:请求锁定所有表之后再备份,对MyISAM、InnoDB、Aria做温备。
  • –lock-tables:备份哪张表,就锁定哪张表。这种并不理想,不建议使用,使用上面的那个。
  • –single-transaction: 能够对InnoDB存储引擎实现热备;
1
2
3
4
[root@db ~]# mysqldump -uroot -hlocalhost -p hellodb --lock-all-tables >/root/hellodb.sql
Enter password:
[root@db ~]# mysqldump -uroot -hlocalhost -p --databases hellodb --lock-all-tables >/root/hellodb2.sql
Enter password:

【注意】:上面两句,第二句在备份单个表时也加了–databases参数,这样备份后的文件里是有CREATE DATABASE语句的。但是–lock-all-tables这种方式也不是很理想,其他的请求会被阻塞,如果你能确保你要备份的数据库的表的底层存储引擎都是InnoDB的话,可以使用另外一种备份方式,–single-transaction,基于多版本并发控制完成对InnoDB存储的热备,和–lock-all-tables不要同时使用。

备份代码:mysqldump只备份数据,不备份代码。

  • –events: 备份事件调度器代码
  • –routines: 备份存储过程和存储函数
  • –triggers:备份触发器

备份时滚动日志:

--flush-logs: 备份前、请求到锁之后滚动日志。

为什么要滚动日志呢?恢复是要采用完全备份+增量备份或差异备份,最后是恢复不到数据损坏的那一刻的,比如你周日做的完全备份,周三中午崩掉了,你可以采用完全备份+周一、周二的增量备份,或者完全备份+差异备份,但是你周三凌晨到周三中午的数据怎么恢复?依靠二进制日志。滚动之后,恢复时你就知道从哪个文件向后是要用到的。因此用mysqldump做完全备份时都应该做–flush-logs。

复制时的同步位置标记:
主从复制架构中的主服务器数据,说白了它就是在你没有flush-logs时怎么知道下一次恢复时用这个文件怎么恢复到时间点。–master-data帮我们备份那一刻二进制日志的文件名及事件所处的位置。

--master-data=[0|1|2]
  0: 不记录
  1:记录为CHANGE MASTER语句
  2:记录为注释的CHANGE MASTER语句

【总结】:使用mysqldump备份需要使用的参数:

  • 请求锁:–lock-all-tables或使用–singe-transaction进行innodb热备;
  • 滚动日志:–flush-logs
  • 选定要备份的库:–databases
  • 记录二进制日志文件及位置:–master-data=

mysqldump备份示例

【示例1】:手动施加锁,然后进行备份。


【注意】:刷写所有表:把所有表在缓冲区中的内容通通同步到磁盘上。如果你的数据量很大,这句刷写和加锁语句要等很长时间。
然后用mysqldump备份就可以了。

[root@db ~]# mysqldump -uroot -p --databases hellodb >/tmp/hellodb2.sql
Enter password: 

备份完了记得释放锁:

mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)

【示例2】:手动施加锁太麻烦,直接用mysqldump备份。

[root@db ~]# mysqldump -uroot -p --databases hellodb --lock-all-tables --flush-logs >/tmp/hellodb3.sql
Enter password: 

如果有代码块,也需要把相应选项加进来。

  • –events: 备份事件调度器代码
  • –routines: 备份存储过程和存储函数
  • –triggers:备份触发器

热备,你得确定库中所有表的存储引擎都是InnoDB存储引擎

[root@db ~]# mysqldump -uroot -p --databases hellodb --single-transaction --flush-logs >/tmp/hellodb4.sql                 
Enter password: 

还应该指定–master-data=[0|1|2]

[root@db ~]# mysqldump -uroot -p --databases hellodb --lock-all-tables --flush-logs --master-data=2 >/tmp/hellodb5.sql
Enter password: 
[root@db ~]# vim /tmp/hellodb5.sql 

恢复:
建议:临时性关闭二进制日志,关闭其它用户连接。因为恢复时经常会创建数据库,创建表,插入数据,这部分没必要记录二进制日志。用这个备份恢复时只能恢复到上一次完全备份的位置,要想做时间点还原,还需要二进制日志。

【示例3】:数据库即时点恢复。

[root@db ~]# mysqldump -uroot -p --databases hellodb --lock-all-tables --flush-logs --master-data=2 >/tmp/hellodb6.sql
Enter password: 

备份后,我们在hellodb库中创建了表,插入了一些数据。

1
2
3
4
5
6
7
8
9
10
11
mysql> use hellodb
Database changed
mysql> create table newtable(Name CHAR(30));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into newtable values ('Tom'),('Jerry');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> quit
Bye

没注意把数据库hellodb删除了

1
2
3
4
5
mysql> DROP DATABASE hellodb;
Query OK, 8 rows affected (0.03 sec)
mysql> quit
Bye

恢复过程:
①让服务器离线,最起码你得保证服务器不能被别人连进来。
开启防火墙或者其他。

②把即时点前的二进制日志导出来。

二进制日志是master-bin.000013的120位置。

[root@db ~]# vim /tmp/hellodb6.sql 
[root@db ~]# cd /data/binlog/
[root@db binlog]# mysqlbinlog --start-position=120 master-bin.000013 #这个日志文件和文件名是在配置文件中定义的

[root@db binlog]# mysqlbinlog --start-position=120 --stop-position=446 master-bin.000013 >/tmp/helldb6.inc.sql

③连上mysql服务器做恢复,先临时性关闭二进制日志

千万不要xshell另起一个会话,导入完全备份,因为session sql_log_bin=0只对当前会话生效,另起一会话导入备份,那么同时也会写到二进制日志中,这是我们不期望的。

④恢复到即时点。



但事实上这个开不开没什么影响,只要你自己不在当前session中操作就行。

【总结】:备份策略:基于mysqldump
1.备份:mysqldump+二进制日志文件
周日做一次完全备份:备份的同时滚动日志
周一至周六:备份二进制日志;(可以每天都FLUSH LOGS,然后把备份之前的那个二进制日志,每天备份每天的二进制日志,直接copy就可以备份二进制日志文件。这里其实是把二进制日志当增量备份)。
2.恢复
完全备份+各二进制日志文件中至此刻的事件
日志滚动也可以使用mysqladmin工具:

[root@db binlog]# mysqladmin -uroot -p flush-logs
Enter password: 

对MySQL配置文件,以及与MySQL相关的OS配置文件在每次修改后都应该直接进行备份。cp一份放在一个地方就行。

我们可以写一个备份脚本:
1、备份所有数据库;
2、在每周日凌晨自动执行;
【注意】:crontab的PATH环境变量和系统的PATH环境变量是不一样的,无论你在命令行中使用命令多么顺当,在crontab中未必会执行,所以你写一个脚本的目的不是在命令行中执行,而是在crontab中执行,请使用命令全路径。