MySQL数据库备份与恢复
2019/08/18 16:33:13 来源:Linux社区 作者:Linux

随着自动化办公与电子商务的不断发展,企业对于信息系统的依懒性越来越高,而数据库在信息系统中担任着非常重要的角色。尤其一些对数据可靠性要求非常高的行业,如银行、证券、电信等,如果发生意外宕机或数据丢失,其损失是非常严重的。为此数据库管理员必须针对具体的业务要求制定详细的数据库备份与灾难恢复的策略,并通过模拟故障对每种可能的情况进行严格的测试,从而保证数据的可靠性。

通过
文1:CentOS 7 编译安装MySQL数据库系统已经掌握MySQL数据库的安装方式;
文2:MySQL数据库基本语句已经掌握了数据库的基本操作。接下来我们了解一下如何对MySQL数据库的备份与恢复。

如果想要掌握mysql数据库的备份,那么以下知识点是必须要了解并掌握的:

数据库备份的重要性
在企业中数据的价值至关重要,数据保障了企业业务的正常运行。因此,数据的安全性及数据的可靠性是运维的重中之重,任何数据的丢失都可能对企业都可能对企业产生严重的后果。通常情况下造成数据丢失的原因有如下几种:
1.程序错误;
2.人为操作错误;
3.运算错误;
4.磁盘故障;
5.灾难(如火灾、地震)和盗窃。

数据库备份类型

1)从物理与逻辑的角度
数据库备份可以分为物理备份与逻辑备份。
物理备份是对数据库操作系统的物理文件的备份。这种备份类型适用于出现问题时需要快速恢复的大型重要数据库;
物理备份又可分为冷备份、热备份和温备份:
冷备份:在数据库关闭状态下进行备份操作;
热备份:在数据库处于运行状态时进行备份操作;
温备份:数据库锁定表格(不可写可读)的状态下进行备份。
逻辑备份是对数据库逻辑组件的备份,表示为逻辑数据库结构和内容的信息。这种类型的备份适用于可以编辑数据值或表结构较小的数据量,或者在不同的机器体系结构下重新创建数据。

2)数据库的备份策略角度
从数据库的备份策略角度,数据库的备份可分为完全备份、差异备份和增量备份。

完全备份:每次对数据进行完整的备份,即对整个数据库的备份,数据库结构和文件结构的备份,保存的是备份完成时刻的数据库,是差异备份和增量备份的基础
完全备份的备份与恢复操作都非常简单,但是数据存在大量的重复,并且会占用大量的磁盘空间,备份时间也较长;

差异备份:备份那些自从上次备份之后被修改的所有文件,备份的时间点是从上次完整备份起,备份的数据越来越大;
恢复数据时,只需恢复上次的完全备份与最近的一次差异备份;

增量备份:只有那些在上次完全备份或增量备份后被修改的文件才会备份。以上次完整备份或上次的增量备份的时间为时间点,仅备份这之间的数据变化,因而备份的数据量少,占用空间小,备份速度快;
恢复数据时,需要上一次的完整备份开始到最后一次增量备份之间的所有增量依次恢复,如中间某次的备份数据损坏,将导致数据的丢失。

常见的备份方式

1)物理冷备份
物理冷备份是需要子啊数据库处于关闭的状态下,能够较好地保证数据库的完整性。物理冷备份一般用于非核心业务,这类业务一般允许中断,物理冷备份的特点就是速度快,恢复时也是最为简单的。通常通过直接打包数据库文件夹来实现备份;

2)专用备份工具mysqldump或mysqlhotcopy

mysqldump是客户端常用逻辑备份程序,能够产生一组被执行以再现原始数据库对象定义和表数据的SQL语句。它可以转储一个到多个MySQL数据库,对其进行备份或传输到远程SQL服务器。mysqldump更为通用,因为它可以备份各种表,mysqldump使用图mysql的不同版本

mysqlhotcopy是由Tim Bunce最初编写和贡献的Perl脚本。mysqlhotcopy仅用于备份MyISAM和ARCHIVE表。它只能运行在UNIX和Linux上,并且mysqlhotcopy仅适用于某些存储引擎。因为使用范围很小,这里认识即可,不多做介绍。

3)通过启动二进制日志进行增量备份
MySQL支持增量备份,进行增量备份时必须启用二进制日志。二进制日志文件为用户提供复制,对执行备份点后进行的数据库更改所需的信息进行恢复。如果进行增量备份,需要刷新二进制日志。

此外还有很多第三方工具,这里也就不一一介绍了!

接下来我们来了解MySQL数据库备份的方法。

物理冷备份与恢复
物理冷备份一般使用tar命令直接打包数据库文件夹即可,但是进行备份之前必须关闭MySQL数据库。

1)备份数据库

[root@localhost ~]# systemctl stop mysqld             //停止MySQL服务
[root@localhost ~]# mkdir /backup                         //新建文件夹,用于存放备份
[root@localhost ~]# tar zcf /backup/mysql-$(date +%F).tar.gz /usr/local/mysql/data
//用tar命令将MySQL服务的根目录复制到指定目录。
[root@localhost ~]# ll /backup                       //查看备份成功的tar包
-rw-r--r--. 1 root root 741234 723 17:00 mysql-2019-07-23.tar.gz

2)模拟故障

[root@localhost ~]# mkdir /bak
[root@localhost ~]# mv /usr/local/mysql/data /bak

3)恢复数据库

[root@localhost ~]# tar zxf /backup/mysql-2019-07-23.tar.gz -C /
//将tar包解压到指定路径,包中已经包含路径,所以只打“/”即可!
[root@localhost ~]# ls /usr/local/mysql/            //查看是否存在data目录
bin      data  include  man     my-new.cnf  README   share      support-files
COPYING  docs  lib      my.cnf  mysql-test  scripts  sql-bench
[root@localhost ~]# systemctl start mysqld       //启动mysql服务

物理冷备份到这里已经完成!

mysqldump备份与恢复
通过mysqldump命令可以将指定的库、表或全部的库导出为SQL脚本,便于该命令在不同版本的MySQL服务器上使用。

1)备份数据库
实验环境,mysql管理员没有密码,如果有密码使用“”-p”选项

[root@localhost ~]# mysqldump -u root mysql user > mysql-user.sql
//将mysql库中user表保存为“mysql-user.sql”SQL脚本(库名和表名之间用空格分割)
[root@localhost ~]# mysqldump -u root --database mysql > mysql.sql
//将mysql库保存为“mysql.sql”SQL脚本
[root@localhost ~]# mysqldump -u root  --opt --all-databases > all-data.sql
//将mysql数据库中的所有库做一个备份,保存为“all-data.sql”SQL脚本文件
//时间较长可以使用“--opt”执行优化速度
[root@localhost ~]# ls     //查看备份的脚本文件是否存在
all-data.sql     cmake-2.8.6.tar.gz    mysql-5.6.36.tar.gz  mysql-user.sql
anaconda-ks.cfg  initial-setup-ks.cfg  mysql.sql

备份文件是可以查看的,可以使用“cat”、“more”、“grep”等文本工具进行查看。

2)模拟故障并恢复数据库

[root@localhost ~]# mysql -u root -e 'drop table mysql.user;'
[root@localhost ~]# mysql -u root -e 'show tables from mysql;'
//“-e”选项用来不进入数据库的情况下输入SQL语句并显示结果
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
+---------------------------+
//确认user表已经不存在

当备份文件中只包含表的备份,执行导入操作时必须指定库名,且目标库必须已经存在;
若备份文件已经包括完整的库信息,则执行导入操作时无需指定库名。

[root@localhost ~]# mysql -u root mysql < mysql-user.sql 
//使用mysql库user表的备份恢复user表
[root@localhost ~]# mysql -u root -e 'show tables from mysql;'
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
//确认结果信息,user表已经恢复
[root@localhost ~]# mysql -u root -e 'drop database mysql;'
//模拟删除mysql数据库
[root@localhost ~]# mysql -u root -e 'show databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| performance_schema |
| test               |
+--------------------+
[root@localhost ~]# mysql -u root < mysql.sql
//恢复时前面既不打表名,也不打库名
[root@localhost ~]# mysql -u root -e 'show databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+

当然,备份整个mysql数据库的SQL语句文件,可以恢复任意一个库或表。

mysql增量备份与恢复

增量备份的特点
与完全备份不同,增量备份没有重复数据,备份量较小,备份时间短;但其恢复麻烦,需要上次完全备份及完全备份之后所有的增量备份才能恢复,而且要对增量备份进行逐个反推恢复。MySQL并没有提供直接的增量备份方法,可以通过MySQL提供的二进制日志间接实现增量备份。

mysql二进制日志对备份的意义
二进制日志保存了所有更新或者可能更新数据库的操作。二进制日志在启动MySQL服务器后开始记录,并在文件达到二进制日志所设置的最大值或者接收到“flush logs”命令后重新创建新的日志文件,生成二进制文件序列,并及时把这些日志保存到安全的存储位置,即可完整一个时间段的增量备份。

要想进行MySQL的增量备份,首先必须开启二进制日志功能。

[root@localhost ~]# vim /etc/my.cnf                //编写mysql服务的主配置文件
                 …………     //省略部分内容,添加以下内容
log-bin=/usr/local/mysql/mysql-bin            //二进制日志的存放位置
[root@localhost ~]# systemctl restart mysqld             //重启mysql服务
[root@localhost ~]# ll /usr/local/mysql/mysql-bin.*        //查看二进制日志文件    
-rw-rw----. 1 mysql mysql 120 723 18:00 /usr/local/mysql/mysql-bin.000001
-rw-rw----. 1 mysql mysql  34 723 18:00 /usr/local/mysql/mysql-bin.index
//现在对mysql数据库的操作将记录在mysql-bin.000001文件中

mysql增量恢复常见的方法有三种:
一般恢复:将所有备份的二进制日志文件内容全部恢复,命令格式:

mysqlbinlog [--no-defaults] 增量备份文件 | mysql -u 用户名 -p

基于位置的恢复:数据库管理员在操作数据库时可能在同一时间点既有错误的操作也有正确的操作,基于位置恢复更加精准:
1.恢复数据到指定位置,命令格式:

mysqlbinlog --stop-position=’操作 id’ 二进制日志 |mysql -u 用户名 -p 密码

2.从指定位置开始恢复数据,命令格式:

mysqlbinlog --start-position=’操作 id’ 二进制日志 |mysql -u 用户名 -p 密码

基于时间点恢复:跳过某个发生错误的时间点实现数据恢复。而基于时间点的恢复可以分为三种情况:
1.从日志开头截止到某个时间点的恢复,命令格式:

mysqlbinlog [--no-defaults] --stop-datetime=’年-月-日 小时:分钟:秒’ 二进制日志 | mysql -u 用户名 -p 密码

2.从某个时间点到日志结尾的恢复,命令格式:

mysqlbinlog [--no-defaults] --start-datetime=’年-月-日 小时:分钟:秒’ 二进制日志 | mysql -u 用户名 -p 密码

3.从某个时间点到某个时间点的恢复,命令格式:

mysqlbinlog [--no-defaults] --start-datetime=’年-月-日 小时:分钟:秒’ --stop-datetime=’年-月-日小时:分钟:秒’ 二进制日志 | mysql -u 用户名 -p 密码

通过一个小事例了解一下:

[root@localhost ~]# mysql -u root -e 'select * from a.t1;'
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
//新建a库t1表,并往表中插入三条数据。
[root@localhost ~]# mysqldump -u root a t1 > a_t1_$(date +%F).sql
//先做一次完全备份
[root@localhost ~]# mysqladmin -u root flush-logs
//刷新二进制日志
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(4);'
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(5);'
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(6);'
//插入三条新数据
[root@localhost ~]# mysqladmin -u root flush-logs
//再刷新二进制日志
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(7);'
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(8);'
[root@localhost ~]# mysql -u root -e 'insert into a.t1 values(9);'
[root@localhost ~]# mysql -u root -e 'delete from a.t1;'
//插入三条记录并删除表中所有数据
[root@localhost ~]# mysqladmin -u root flush-logs
//刷新二进制日志
[root@localhost ~]# mysql -u root -e 'select * from a.t1;'
//查看表,表中已经没有任何数据

一般恢复

[root@localhost ~]# mysql -u root a < /root/a_t1_2019-07-23.sql 
//先执行完整恢复
[root@localhost ~]# mysql -u root -e 'select * from a.t1;'
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
//查看表中内容已经恢复出了三条数据
[root@localhost ~]# cd /usr/local/mysql                        //进入存放二进制文件的目录
[root@localhost mysql]# mysqlbinlog --no-defaults mysql-bin.000002 | mysql -u root
//使用第二个二进制文件恢复数据(因为456数据存放在第二个二进制文件中)
[root@localhost mysql]# mysql -u root -e 'select * from a.t1;'
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
|    6 |
+------+
//再次查看已经恢复完成!

基于位置恢复

[root@localhost mysql]# mysql -u root -e 'drop table a.t1;'
//删除a.t1表本身
[root@localhost mysql]# mysql -u root -e 'select * from a.t1;'
ERROR 1146 (42S02) at line 1: Table 'a.t1' doesn't exist
//查看表确实不存在
[root@localhost mysql]# mysql -u root a < /root/a_t1_2019-07-23.sql 
//先执行完整恢复
[root@localhost mysql]# mysqlbinlog --no-defaults mysql-bin.000003
//使用mysqlbinlog工具查看第三个二进制文件(第三个文件中包含删除的操作)
                             ………………    //省略部分内容,找到删除语句
# at 780        //操作ID
#190723 18:24:51 server id 1  end_log_pos 863 CRC32 0x46540b40  Query   thread_id=12    exec_time=0 error_code=0
SET TIMESTAMP=1563877491/*!*/;
delete from a.t1
                     ……………………            //省略部分内容,二进制文件中内容太多,耐心寻找
[root@localhost mysql]# mysqlbinlog --no-defaults --stop-position='780' mysql-bin.000003 | mysql -u root
//恢复删除之前的数据
[root@localhost mysql]# mysql -u root -e 'select * from a.t1;'
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    7 |
|    8 |
|    9 |
+------+

基于时间点的恢复

[root@localhost mysql]# mysql -u root -e 'drop table a.t1;'
//删除a.t1表本身
[root@localhost mysql]# mysql -u root -e 'select * from a.t1;'
ERROR 1146 (42S02) at line 1: Table 'a.t1' doesn't exist
//查看表确实不存在
[root@localhost mysql]# mysql -u root a < /root/a_t1_2019-07-23.sql 
//先执行完整恢复
[root@localhost mysql]# mysqlbinlog --no-defaults mysql-bin.000003
//使用mysqlbinlog工具查看第三个二进制文件(第三个文件中包含删除的操作)
                         …………     //省略部分内容
# at 388      
#190723 18:24:33 server id 1  end_log_pos 481 CRC32 0x3861b619  Query   thread_id=10    exec_time=0 error_code=0                                        //找到插入数据8的记录,记住时间
SET TIMESTAMP=1563877473/*!*/;
insert into a.t1 values(8)
/*!*/;
# at 481
#190723 18:24:33 server id 1  end_log_pos 512 CRC32 0xa7550b63  Xid = 57
COMMIT/*!*/;
# at 512
#190723 18:24:37 server id 1  end_log_pos 584 CRC32 0xd9c5c9a4  Query   thread_id=11    exec_time=0 error_code=0
SET TIMESTAMP=1563877477/*!*/;
BEGIN
/*!*/;
# at 584
#190723 18:24:37 server id 1  end_log_pos 677 CRC32 0xf15c7ff8  Query   thread_id=11    exec_time=0 error_code=0                                         //找到插入数据9的记录,记住时间
SET TIMESTAMP=1563877477/*!*/;
insert into a.t1 values(9)
/*!*/;
现在只恢复数据8
[root@localhost mysql]# mysqlbinlog --no-defaults --start-datetime='2019-07-23 18:24:33' --stop-datetime='2019-07-23 18:24:37' mysql-bin.000003 | mysql -u root
//开始时间和结束时间没写错,恢复就没有问题,注意格式
[root@localhost mysql]# mysql -u root -e 'select * from a.t1;'
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    8 |
+------+
//再次查看数据8已经恢复

不管使用增量恢复哪种方式恢复,都必须先恢复完整恢复!!!

无论选择完全备份,还是选择增量备份,都需考虑它们的优缺点,是否适合当前的生产环境,同时,为了保证恢复的完整性,建议开启二进制日志功能,二进制日志文件给恢复工作带来了很大的灵活性,可以基于时间点或位置进行恢复。考虑到数据库性能,我们可以将二进制日志文件保存到其他安全的硬盘中。

进行备份将会占用大量的MySQL服务器的资源,建议在晚上的时候进行备份,避免导致数据库性能下降!!!

Linux公社的RSS地址https://www.linuxidc.com/rssFeed.aspx

本文永久更新链接地址https://www.linuxidc.com/Linux/2019-08/160180.htm


7

本栏最新