备份的主要目的是灾难恢复,备份还可以测试应用,回滚数据修改,查询历史数据,审计等。我们将从生产运维的角度了解备份恢复的分类与方法。
在企业中数据的价值至关重要,数据保障了企业业务的运行,因此数据的安全性及可靠性是运维的重中之重,任何数据的丢失都有可能会对企业产生严重的后果。造成数据丢失的原因如下:
- 程序错误
- 人为错误
- 数据泄露
- 运算失败
- 磁盘故障
- 灾难(如火灾、地震)
数据库类型
物理和逻辑备份
脱机备份(冷备备份)和联机备份(热备份)
1,冷备份:关闭数据库的状态进行
2,热备份:在数据库运行状态进行,这种备份方法可依赖于数据库的日志问价
3,温备份:数据库锁定表(不可写入但可读)的状态下进行
逻辑备份:对数据库逻辑组件(如表等数据库对象)的备份,表示为逻辑数据库结构(create database、create table等语句)和内容(insert语句或分割文本文件)的信息。这种类型的备份适用于可以编辑数据值或表结构较小的数据量,或者在不同机器体系结构上重新创建数据。
2.2 从数据库的备份策略角度
备份可分为完全备份、差异备份和增量备份
完全备份:每次对数据进行完整的备份,即对整个数据库的备份、数据库结构和文件结构的备份,保存的是备份完成时刻的数据库状态,是差异备份与增量备份的基础。
优点:备份与恢复操作简单方便
缺点:数据存在大量的重复;占用大量的空间;备份与恢复时间长
差异备份:备份那些自从上次完全备份之后被修改过的所有文件,备份的时间起点是从上次完整备份起,备份数据量会越来越大。恢复数据时,只需恢复上次的完全备份与最近的一次差异备份。
增量备份:只有那些在上次完全备份或者增量备份后被修改的文件才会被备份。以上次完整备份或上次的增量备份的时间为时间点,仅备份这之间的数据变化,因而备份的数据量小,占用空间小,备份速度快。但恢复时,需要从上一次的完整备份起到最后一次增量备份依次恢复,如中间某次的备份数据损坏,将导致数据的丢失。
2.3 常见的备份方法
MySQL数据库的备份可以采用很多种方式,如直接打包数据库文件(物理冷备份),专用备份工具(mysqldump),二进制日志增量备份,第三方工具备份等。
- 物理备份
物理冷备份时需要在数据库处于关闭状态下,能够较好的保证数据库的完整性。物理冷备份以用于非核心业务,这类业务都允许中断,物理冷备份的特点就是速度快,恢复时也是最为简单的,通过直接打包数据库文件夹(/usr/local/mysql/data)来实现备份。
- 专用备份工具mysqldump或mysqlhotcopy
mysqldump和mysqlhotcopy都可以做备份。mysqldump是客户端常用逻辑备份程序,能够产生一组被执行以再现原始数据库对象定义和表数据的SQL语句。它可以转储一个到多个MySQL数据库,其进行备份或传输到远程SQL服务器。mysqldump更为通用,因为它可以备份各种表。mysqlhotcopy仅适用于某些存储引擎。
mysqlhotcopy是由Tim Bunce最初编写和贡献的Perl脚本。mysqlhotcopy仅用于备份MyISAM和ARCHIVE数据表。只能运行在Unix或Linux操作系统上。
- 通过启用二进制(binary log,binlog)日志进行增量备份
MySQL支持增量备份,进行增量备份时必须启用二进制日志。二进制日志文件为用户提供复制。对执行备份点后进行的数据库更改所需的信息进行备份。如果进行增量备份(包含上次完全备份或增量备份以来发生的数据修改),需要刷新二进制日志。
- 通过第三方工具备份
Percona XtraBackup是一个免费的MySQL热备份软件,支持在线备份Innodb和XtraDB,也可以支持MySQL表备份,不过MyISAM表的备份要在表锁的情况进行。
Percona XtraBackup主要的工具:xtrabackup、innobackupex、xbstream
- xtrabackup:是一个编译了的二进制文件,只能备份Innodb/Xtradb数据文件
- innobackupex:是一个封装了xtrabackup的Perl脚本,除了可以备份Innodb/Xtradb之外,还可以备份MyISAM。
- xbstream:是一个新组件,能够允许将文件格式转换成xbstream格式或从xbstream格式转到文件格式。
xtrabackup工具可以单独使用,但推荐使用innobackupx来进行备份,因为其本身已经包含了xtrabackup的所有功能。
xtrabackup是基于Innodb的灾难恢复功能进行设计的,备份工具复制Innodb的数据文件,但是由于不锁表,这样复制出来的数据将不一致,Innodb维护了一个重要日志,包含Innodb数据的所有改动情况。在xtrabackup备份Innodb的数据同时,xtrabackup还有另外一个线程用来监控重做日志,一旦日志发生变化,就把发生变化的日志数据复制走。这样就可利用重做日志做灾难恢复了。
以上是备份过程,如果我们需要恢复数据,则在准备阶段,xtrabackup就需要使用之前复制的重做日志对备份出来的Innodb数据文件进行灾难恢复,此阶段完成之后,数据库就可以进行重建还原了。
Percona Xtrabackup对MyISAM的复制是按顺序进行的,先锁定表,然后复制,再解锁表。
三、MySQL完全备份操作
MySQL数据库的完全备份可以采用多种方式,物理冷备份一般用tar命令直接打包数据库文件夹(数据目录),而在备份前需要先停库。
1、直接打包数据库文件夹,源码包的位置/usr/local/mysql/data/,rpm包的位置 /var/lib/mariadb/
示例:
[root@localhost ~]# /etc/init.d/mysqld start
Starting MySQL............... SUCCESS!
[root@localhost ~]# netstat -lnpt | grep :3306
tcp6 0 0 :::3306 :::* LISTEN 1630/mysqld
[root@localhost ~]# mysql -u root -p123456
mysql> create database auth;
Query OK, 1 row affected (0.00 sec)
mysql> use auth;
Database changed
mysql> create table user(name char(10) not null,ID int(48));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into user values('crushlinux','123');
Query OK, 1 row affected (0.01 sec)
mysql> select * from user;
+------------+------+
| name | ID |
+------------+------+
| crushlinux | 123 |
+------------+------+
1 row in set (0.00 sec)
mysql> exit
Bye
[root@localhost ~]# /etc/init.d/mysqld stop
Shutting down MySQL.. SUCCESS!
[root@localhost ~]# mkdir backup
[root@localhost ~]# tar jcf backup/mysql_all-$(date +%F).tar.gz /usr/local/mysql/data/
tar: Removing leading `/' from member names
[root@localhost ~]# ls -l backup/
总用量 728
-rw-r--r-- 1 root root 742476 12月 14 23:31 mysql_all-2018-12-14.tar.gz
模拟数据丢失:
[root@localhost ~]# /etc/init.d/mysqld start
Starting MySQL.. SUCCESS!
[root@localhost ~]# mysql -uroot -p123456
mysql> drop database auth;
Query OK, 1 row affected (0.02 sec)
恢复数据:
[root@localhost ~]# /etc/init.d/mysqld stop
Shutting down MySQL.. SUCCESS!
[root@localhost ~]# mkdir restore
[root@localhost ~]# tar xf backup/mysql_all-2020-04-23.tar.gz -C restore/
[root@localhost ~]# rm -rf /usr/local/mysql/data/*
[root@localhost ~]# mv restore/usr/local/mysql/data/* /usr/local/mysql/data/
[root@localhost ~]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from auth.user;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+------+
| name | ID |
+------------+------+
| crushlinux | 123 |
+------------+------+
2、使用专用备份工具mysqldump
MySQL自带的备份工具mysqldump,可以很方便的对MySQL进行备份。通过该命令工具可以将数据库、数据表或全部的库导出为SQL脚本,便于该命令在不同版本的MySQL服务器上使用。例如,当需要升级MySQL服务器时,可以先使用mysqldump命令将原有库信息到导出,然后直接在升级后的MySQL服务器中导入即可。
(1)对单个库进行完全备份
格式:mysqldump -u用户名 -p[密码] [选项] --databases [数据库名] > /备份路径/备份文件名
示例:
[root@localhost ~]# mysqldump -uroot -p123456 --databases auth > backup/auth-$(date +%Y%m%d).sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@localhost ~]# cat backup/auth-20181214.sql
(2)对多个库进行完全备份
格式:mysqldump -u用户名 -p [密码] [选项] --databases 库名1 [库名2]… > /备份路径/备份文件名
示例:
[root@localhost ~]# mysqldump -uroot -p123456 --databases mysql auth > backup/mysql+auth-$(date +%Y%m%d).sql
[root@localhost ~]# cat backup/mysql+auth-20181214.sql
(3)对所有库进行完全备份
格式:mysqldump -u用户名 -p [密码] [选项] --opt --all-databases > /备份路径/备份文件名
示例:
[root@localhost ~]# mysqldump -uroot -p123456 --opt --all-databases > backup/mysql_all.$(date +%Y%m%d).sql
[root@localhost ~]# cat backup/mysql_all.20181214.sql
//--opt 加快备份速度,当备份数据量大时使用
[root@localhost ~]# cat backup/mysql_all.20160505.sql
(4)对表进行完全备份
格式:mysqldump -u用户名 -p [密码] [选项] 数据库名 表名 > /备份路径/备份文件名
示例:
[root@localhost ~]# mysqldump -uroot -p123456 auth user > backup/auth_user-$(date +%Y%m%d).sql
[root@localhost ~]# cat backup/auth_user-20181214.sql
(5)对表结构的备份
格式:mysqldump -u用户名 -p [密码] -d 数据库名 表名 > /备份路径/备份文件名
示例:
[root@localhost ~]# mysqldump -uroot -p123456 -d mysql user > backup/desc_mysql_user-$(date +%Y%m%d).sql
[root@localhost ~]# cat backup/desc_mysql_user-20181214.sql
四、使用mysqldump备份后,恢复数据库
1、source命令
登录到MySQL数据库,执行source 备份sql脚本路径
示例:
[root@localhost ~]# mysql -uroot -p123456
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| mysql |
| performance_schema |
| test |
| usr |
+--------------------+
6 rows in set (0.00 sec)
mysql> drop database auth;
Query OK, 1 row affected (0.12 sec)
mysql> source backup/auth.20181214.sql
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| mysql |
| performance_schema |
| test |
| usr |
+--------------------+
6 rows in set (0.00 sec)
2、mysql命令
格式:mysql -u用户名 -p [密码] < 库备份脚本的路径
mysql -u用户名 -p [密码] 库名 < 表备份脚本的路径
示例:
[root@localhost ~]# mysql -uroot -p123456 -e 'show databases;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| mysql |
| performance_schema |
| test |
| usr |
+--------------------+
[root@localhost ~]# mysql -uroot -p123456 -e 'drop database auth;'
[root@localhost ~]# mysql -uroot -p123456 < backup/auth.20181214.sql
[root@localhost ~]# mysql -uroot -p123456 -e 'show databases;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| mysql |
| performance_schema |
| test |
| usr |
+--------------------+
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table auth.user;'
[root@localhost ~]# mysql -uroot -p123456 auth< backup/auth_user-20181214.sql
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from auth.user;'
+------------+------+
| name | ID |
+------------+------+
| crushlinux | 123 |
+------------+------+
五、MySQL备份思路
1、定期实施备份,制定备份计划或策略,并严格遵守。
2、除了进行完全备份,开启MySQL服务器的binlog日志功能是很重要的(完全备份加上日志,可以对MySQL进行最大化还原)。
3、使用统一和易理解的备份名称,推荐使用库名或者表名加上时间的命名规则,如mysql_user-20181214.sql,不要使用backup1或者abc之类没有意义的名字。
六、MySQL完全备份案例
需求描述:
用户信息数据库为client,用户资费数据表为user_info,表结构如下所示。请为该公司制定合理的备份策略,依据所制定的策略备份数据,模拟数据丢失进行数据恢复。
创建数据及表,录入数据:
[root@localhost ~]# mysql -uroot -p123456
mysql> show variables like 'character_set_%'; //查看字符集是否支持中文
+--------------------------+----------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.01 sec)
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
character_set_server=utf8
[root@localhost ~]# /etc/init.d/mysqld restart
mysql> show variables like 'character_set_%';
+--------------------------+----------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/charsets/ |
+--------------------------+----------------------------------+
8 rows in set (0.01 sec)
mysql> create database client;
Query OK, 1 row affected (0.00 sec)
mysql> use client;
Database changed
create table user_info(身份证 int(20),姓名 char(20),性别 char(2),用户ID号 int(110),资费 int(10)) DEFAULT CHARSET=utf8;
insert into user_info values('000000001','孙空武','男','011','100');
insert into user_info values('000000002','蓝凌','女','012','98');
insert into user_info values('000000003','姜纹','女','013','12');
insert into user_info values('000000004','关园','男','014','38');
insert into user_info values('000000004','罗中昆','男','015','39');
mysql> select * from user_info;
+-----------+-----------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+-----------+--------+-------------+--------+
| 1 | 孙空武 | 男 | 11 | 100 |
| 2 | 蓝凌 | 女 | 12 | 98 |
| 3 | 姜纹 | 女 | 13 | 12 |
| 4 | 关园 | 男 | 14 | 38 |
| 4 | 罗中昆 | 男 | 15 | 39 |
+-----------+-----------+--------+-------------+--------+
5 rows in set (0.00 sec)
完整备份client.user_info表:
[root@localhost ~]# mysqldump -uroot -p123456 client user_info > backup/client.user_info-$(date +%Y%m%d).sql
模拟数据丢失恢复数据:
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 -e 'use client; show tables;'
[root@localhost ~]# mysql -uroot -p123456 client < backup/client.user_info-20181214.sql
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
+-----------+-----------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+-----------+--------+-------------+--------+
| 1 | 孙空武 | 男 | 11 | 100 |
| 2 | 蓝凌 | 女 | 12 | 98 |
| 3 | 姜纹 | 女 | 13 | 12 |
| 4 | 关园 | 男 | 14 | 38 |
| 4 | 罗中昆 | 男 | 15 | 39 |
+-----------+-----------+--------+-------------+--------+
定期备份数据:
[root@localhost ~]# which mysqldump
/usr/local/mysql/bin/mysqldump
[root@localhost ~]# vim /opt/bak_client.sh
#!/bin/bash
# 备份client.user_info表 脚本
/usr/local/mysql/bin/mysqldump -uroot -p123456 client user_info >backup/client.user_info-$(date +%Y%m%d).sql
[root@localhost ~]# chmod +x /opt/bak_client.sh
[root@localhost ~]# crontab -e
0 0 * * * /opt/bak_client.sh //每天0:00备份
七、MySQL数据库备份脚本
实验环境:
mysql-server:192.168.200.101
mysql-client:192.168.200.102
实验要求:对mysql-server的auth库和client库实现异地备份,每天凌晨2:00进行备份,撰写一个数据恢复脚本。
MySQL服务端授权,给予select和lock tables权限,以备份
[root@localhost ~]# mysql -uroot -p123456
mysql> grant select,lock tables on auth.* to 'admin'@'192.168.200.102' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> grant select,lock tables on client.* to 'admin'@'192.168.200.102' identified by '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
客户端安装客户端软件
[root@client ~]# yum -y install mysql
连接测试
[root@client ~]# mysql -uadmin -p -h192.168.200.101
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| auth |
| client |
| test |
+--------------------+
4 rows in set (0.00 sec)
撰写客户端备份脚本
[root@client ~]# vim /opt/bakmysql.sh
#!/bin/bash
# MySQL数据库备份脚本
# 设置登录变量
MY_USER="admin"
MY_PASS="123456"
MY_HOST="192.168.200.101"
MY_CONN="-u$MY_USER -p$MY_PASS -h$MY_HOST"
# 设置备份的数据库
MY_DB1="auth"
MY_DB2="client"
# 定义备份路径、工具、时间、文件名
BF_DIR="backup"
BF_CMD="/usr/bin/mysqldump"
BF_TIME=$(date +%Y%m%d-%H%M)
NAME_1="$MY_DB1-$BF_TIME"
NAME_2="$MY_DB2-$BF_TIME"
# 备份为.sql脚本,然后打包压缩(打包后删除原文件)
[ -d $BF_DIR ] || mkdir -p $BF_DIR
cd $BF_DIR
$BF_CMD $MY_CONN --databases $MY_DB1 > $NAME_1.sql
$BF_CMD $MY_CONN --databases $MY_DB2 > $NAME_2.sql
/bin/tar zcf $NAME_1.tar.gz $NAME_1.sql --remove &>/dev/null
/bin/tar zcf $NAME_2.tar.gz $NAME_2.sql --remove &>/dev/null
[root@client ~]# chmod +x /opt/bakmysql.sh
[root@client ~]# /opt/bakmysql.sh
[root@client ~]# ls backup/
auth-20160505-1805.tar.gz client-20160505-1805.tar.gz
[root@client ~]# tar tvf backup/auth-20160505-1805.tar.gz
-rw-r--r-- root/root 1967 2016-05-05 18:05 auth-20160505-1805.sql
[root@client ~]# tar tvf backup/client-20160505-1805.tar.gz
-rw-r--r-- root/root 2250 2016-05-05 18:05 client-20160505-1805.sql
[root@client ~]# crontab -e
0 2 * * * /opt/bakmysql.sh
改变系统时间,执行任务计划,模拟每天的备份,为之后的恢复脚本做准备
[root@client ~]# date 050601592016.59 //MMDDhhmmYY.SS 月日小时分钟.秒
2016年 05月 06日 星期五 01:59:59 CST
[root@client ~]# ls backup/
auth-20160505-1805.tar.gz client-20160505-1805.tar.gz
auth-20160506-0200.tar.gz client-20160506-0200.tar.gz
[root@client ~]# date 050701592016.59
2016年 05月 07日 星期六 01:59:59 CST
[root@client ~]# date 050801592016.59
2016年 05月 08日 星期日 01:59:59 CST
[root@client ~]# ls backup/
auth-20160505-1805.tar.gz auth-20160508-0200.tar.gz client-20160507-0200.tar.gz
auth-20160506-0200.tar.gz client-20160505-1805.tar.gz client-20160508-0200.tar.gz
auth-20160507-0200.tar.gz client-20160506-0200.tar.gz
撰写数据恢复脚本
[root@client ~]# vim /opt/restore_mysql.sh
#!/bin/bash
# 恢复MySQL数据库数据脚本
# 设置变量
MY_USER="admin"
MY_PASS="123456"
MY_HOST="192.168.200.101"
BF_DIR="backup"
mkdir .aaa
ls $BF_DIR |column -t > .aaa/db_list
awk -F'-' '{print $2}' .aaa/db_list > .aaa/dt.txt
read -p "请指定要恢复数据库的日期(YYYYMMDD):" dt
if [ $dt -ge 20160501 ] && [ $dt -le 20160601 ];then
grep "$dt" .aaa/dt.txt &>/dev/null
if [ $? -ne 0 ];then
echo "很抱歉,您恢复数据库的备份日期不再备份日期范围内"
else
echo "搜索到的可恢复数据库如下:"
awk -F'-' /$dt/'{print NR,$1}' .aaa/db_list
read -p "请选择您要恢复数据库的编号: " nb
nm=$(awk -F'-' /$dt/'{print NR,$1}' .aaa/db_list |awk /$nb/'{print $2}')
echo "现在开始恢复数据库:$nm到$dt"
cd $BF_DIR
onm=$(ls |grep "$nm-$dt")
mkdir .bbb
tar xf $onm -C .bbb
mysql -u$MY_USER -p$MY_PASS -h$MY_HOST $nm < .bbb/*
echo "$nm已经恢复到$dt"
rm -rf .bbb
cd - &>/dev/null
rm -rf .aaa
fi
else
echo "很抱歉,您恢复数据库的备份日期不再备份日期范围内"
fi
[root@client ~]# chmod +x /opt/restore_mysql.sh
如在客户端恢复数据,需要开放权限
mysql> grant all on auth.* to 'admin'@'192.168.200.102';
Query OK, 0 rows affected (0.00 sec)
mysql> grant all on client.* to 'admin'@'192.168.200.102';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
恢复测试:
[root@client ~]# /opt/restore_mysql.sh
请指定要恢复数据库的日期(YYYYMMDD):20160507
搜索到的可恢复数据库如下:
3 auth
7 client
请选择您要恢复数据库的编号: 3
现在开始恢复数据库:auth到20160507
auth已经恢复到20160507
[root@client ~]# /opt/restore_mysql.sh
请指定要恢复数据库的日期(YYYYMMDD):20100101
很抱歉,您恢复数据库的备份日期不再备份日期范围内
MySQL增量备份与恢复
一、MySQL增量备份概念
使用mysqldump进行完全备份,备份的数据中有重复数据,备份时间与恢复时间过长。而增量备份就是备份自上一次备份之后增加或改变的文件或内容。
增量备份的特点:
没有重复数据,备份量不大,时间短
恢复麻烦:需要上次完全备份及完全备份之后所有的增量备份才能恢复,而且要对所有增量备份进行逐个反推恢复。
MySQL没有提供直接的增量备份办法,可以通过MySQL提供的二进制日志(binary logs)间接实现增量备份。
MySQL二进制日志对备份的意义:
二进制日志保存了所有更新数据的数据库操作(SQL语句)。
二进制日志在启动MySQL服务器后开始记录,并在文件达到max_binlog_size所设置的大小或者接收到flush-logs命令后重新创建新的日志文件。
[root@localhost ~]# vim /etc/my.cnf
52 max_binlog_size = 1024000 //二进制日志最大1M
只需定时执行flush-logs方法重新创建新的日志,生成二进制文件序列,并及时把这些日志保存到安全的地方就完成了一个时间段的增量备份。
要进行MySQL的增量备份,首先要开启二进制日志功能,开启MySQL的二进制日志功能。
方法一:MySQL的配置文件的[mysqld]项中加入log-bin=文件存放路径/文件前缀,如log-bin=mysql-bin,然后重启mysqld服务。默认此配置存在。
[root@localhost ~]# awk /log-bin/'{print NR,$0}' /etc/my.cnf
[mysqld]
server-id=1
log-bin=mysql-bin
方法二:使用mysqld --log-bin=文件存放路径/文件前缀 重新启动mysqld服务
每周选择服务器负载较轻的时间段,或者用户访问较少的时间段进行备份。
二、MySQL增量恢复
应用场景
- 人为的执行SQL语句破坏了数据库的数据
- 在进行下一次全备之前发生系统故障导致数据库数据丢失
- 在主从同步架构中,主库数据发生了故障,保证从库数据一致性
增量恢复的方法
1、一般的恢复:备份的二进制日志内容全部恢复
格式:mysqlbinlog [--no-defaults] 增量备份文件 | mysql -u用户名 -p密码
2、基于时间点的恢复:便于跳过某个发生错误的时间点实现数据恢复
格式:从日志开头截止到某个时间点的恢复:
mysqlbinlog [--no-defaults] --stop-datetime=’年-月-日 小时:分钟:秒’ 二进制日志 | mysql -u用户名 -p密码
从某个时间点到日志结尾的恢复:
mysqlbinlog [--no-defaults] --start-datetime=’年-月-日 小时:分钟:秒’ 二进制日志 | mysql -u用户名 -p密码
从某个时间点到某个时间点的恢复:
mysqlbinlog [--no-defaults] --start-datetime=’年-月-日 小时:分钟:秒’ --stop-datetime=’年-月-日 小时:分钟:秒’ 二进制日志 | mysql -u用户名 -p密码
3、基于位置的恢复:可能在同一时间点既有错误的操作也有正确的操作,基于位置进行恢复更加精准
格式:
mysqlbinlog --stop-position=’操作id’ 二进制日志 |mysql -u用户名 -p密码
mysqlbinlog --start-position=’操作id’ 二进制日志 |mysql -u用户名 -p密码
三、制定企业备份策略的思路
- 确定当前mysql 是处于哪种表类型下工作的,它们支持事物处理还是非事物的,因为我们需要根据不同的特点来做一些设置。
- 要选择备份的形式是完全备份还是增量备份,它们各有优缺点。
- 为了保证恢复的完整性,我们得开启binary log功能,同时binlog给恢复工作也带来了很大的灵活性,可以基于时间点或是位置进行恢复。考虑到数据库性能,我们可以将binlog文件保存到其他安全的硬盘中。
- 备份操作和应用服务同时运行,这样就十分消耗系统资源了,会导致数据库服务性能下降,这就要求我们选择一个合适的时间(比如在应用负担很小的时候)再来进行备份操作。
- 不是备份完就万事大吉,我们还得确认备份是否可用,所以之后的恢复测试是完全有必要的。
- 根据数据更新频繁,则应该较为频繁的备份
- 数据重要,则在有适当更新时进行备份
- 在数据库压力小的时段进行备份,如一周一次完全备份,然后每天进行增量备份
- 中小公司,全备一般可一天一次
- 大公司可每周进行一次全备,每天进行一次增量备份
- 尽量为企业实现主从复制架构
四、MySQL企业备份案例
需求描述:
用户信息数据库为client,用户资费数据表为user_info
请为该公司每周进行完全备份
每天为该公司进行增量备份
新增加的用户信息如表所示
添加数据库、表,录入数据
[root@localhost ~]# mysql -uroot -p123456
mysql> create database client;
mysql> use client;
mysql> create table user_info(身份证 char(20) not null,姓名 char(20) not null,性别 char(4),用户ID号 char(10) not null,资费 int(10)) DEFAULT CHARSET=utf8;
mysql> insert into user_info values('000000006','张三','男','016','10');
mysql> insert into user_info values('000000007','李四','女','017','91');
mysql> insert into user_info values('000000008','王五','女','018','23');
mysql> select * from user_info;
先进行一次完全备份
[root@localhost ~]# mkdir /mysql_bak
[root@localhost ~]# mysqldump -uroot -p123456 client user_info >/mysql_bak/client_userinfo-$(date +%F).sql
[root@localhost ~]# mysqldump -uroot -p123456 --databases client >/mysql_bak/client-$(date +%F).sql
[root@localhost ~]# ls /mysql_bak/
client-2018-12-14.sql client_userinfo-2018-12-14.sql
进行一次日志回滚(生成新的二进制日志)
[root@localhost ~]# ls /usr/local/mysql/data
client ibdata1 ib_logfile0 ib_logfile1 localhost.localdomain.err mysql mysql-bin.000001 mysql-bin.index mysql.sock test
[root@localhost ~]# mysqladmin -uroot -p123456 flush-logs
[root@localhost ~]# ls /usr/local/mysql/data
client ibdata1 ib_logfile0 ib_logfile1 localhost.localdomain.err mysql mysql-bin.000001 mysql-bin.000002 mysql-bin.index mysql.sock test
继续录入新的数据
[root@localhost ~]# mysql -uroot -p123456
mysql> use client;
mysql> insert into user_info values('000000009','赵六','男','019','37');
mysql> insert into user_info values('0000000010','孙七','男','020','36');
mysql> select * from user_info;
进行增量备份
[root@localhost ~]# mysqladmin -uroot -p123456 flush-logs
[root@localhost ~]# ls /usr/local/mysql/data
client ib_logfile0 localhost.localdomain.err mysql-bin.000001 mysql-bin.000003 mysql.sock ibdata1 ib_logfile1 mysql mysql-bin.000002 mysql-bin.index test
[root@localhost ~]# cp -p /usr/local/mysql/data/mysql-bin.000002 /mysql_bak/
[root@localhost ~]# mysqlbinlog -v /mysql_bak/mysql-bin.000002 //查看新操作的日志记录
模拟误操作删除user_info表
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
ERROR 1146 (42S02) at line 1: Table 'client.user_info' doesn't exist
恢复完全备份
[root@localhost ~]# mysql -uroot -p123456 client < /mysql_bak/client_userinfo-2018-12-14.sql [root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
恢复增量备份
[root@localhost ~]# mysqlbinlog --no-defaults /mysql_bak/mysql-bin.000002 | mysql -u root -p123456
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
基于时间点的增量备份恢复
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
ERROR 1146 (42S02) at line 1: Table 'client.user_info' doesn't exist
[root@localhost ~]# mysql -uroot -p123456 client < /mysql_bak/client_userinfo-2018-12-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults /mysql_bak/mysql-bin.000002
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#181214 12:05:12 server id 1 end_log_pos 106 Start: binlog v 4, server v 5.1.73-log created 181214 12:05:12
BINLOG '
eC1KWA8BAAAAZgAAAGoAAAAAAAQANS4xLjczLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
'/*!*/;
# at 106
#181214 12:05:53 server id 1 end_log_pos 241 Query thread_id=7 exec_time=0 error_code=0
use `client`/*!*/;
SET TIMESTAMP=1481256353/*!*/;
SET @@session.pseudo_thread_id=7/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
insert into user_info values('000000009','赵六','男','019','37')
/*!*/;
# at 241
#181214 12:06:00 server id 1 end_log_pos 374 Query thread_id=7 exec_time=0 error_code=0
SET TIMESTAMP=1481256360/*!*/;
insert into user_info values('0000000010','孙七','男','020','36')
/*!*/;
# at 374
#181214 12:07:25 server id 1 end_log_pos 417 Rotate to mysql-bin.000003 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
仅恢复到12:06:00之前的数据,即不恢复“孙七”的信息
[root@localhost ~]# mysqlbinlog --no-defaults --stop-datetime='2018-12-14 12:06:00' /mysql_bak/mysql-bin.000002 |mysql -uroot -p123456
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
仅恢复“孙七”的信息,跳过“赵六”的信息恢复
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 client < /mysql_bak/client_userinfo-2018-12-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults --start-datetime='2018-12-14 12:06:00' /mysql_bak/mysql-bin.000002 |mysql -uroot -p123456
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
基于位置的恢复
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
ERROR 1146 (42S02) at line 1: Table 'client.user_info' doesn't exist
[root@localhost ~]# mysql -uroot -p123456 client < /mysql_bak/client_userinfo-2018-12-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults --stop-position='241' /mysql_bak/mysql-bin.000002 |mysql -uroot -p123456
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 -e 'drop table client.user_info;'
[root@localhost ~]# mysql -uroot -p123456 client < /mysql_bak/client_userinfo-2018-12-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults --start-position='241' /mysql_bak/mysql-bin.000002 |mysql -uroot -p123456
[root@localhost ~]# mysql -uroot -p123456 -e 'select * from client.user_info;'
五、企业数据库备份脚本
[root@localhost ~]# vim /opt/mysql_bak_wanbei.sh //完全备份脚本
#!/bin/bash
# MySQL数据库完全备份脚本
# 设置登录变量
MY_USER="root"
MY_PASS="123456"
MY_HOST="localhost"
MY_CONN="-u$MY_USER -p$MY_PASS -h$MY_HOST"
# 设置备份的数据库(或表)
MY_DB="client"
# 定义备份路径、工具、时间、文件名
BF_DIR="/mysql_bak/wanbei"
BF_CMD="/usr/bin/mysqldump"
BF_TIME=$(date +%Y%m%d-%H%M)
NAME="$MY_DB-$BF_TIME"
# 备份为.sql脚本,然后打包压缩(打包后删除原文件)
[ -d $BF_DIR ] || mkdir -p $BF_DIR
cd $BF_DIR
$BF_CMD $MY_CONN --databases $MY_DB > $NAME.sql
/bin/tar zcf $NAME.tar.gz $NAME.sql --remove &>/dev/null
[root@localhost ~]# vim /opt/mysql_bak_zengbei.sh //增量备份脚本
#!/bin/bash
# MySQL数据库增量备份脚本
# 设置登录变量
MY_USER="root"
MY_PASS="123456"
MY_HOST="localhost"
MY_CONN="-u$MY_USER -p$MY_PASS -h$MY_HOST"
# 定义备份路径、工具、二进制日志前缀、二进制日志存放路径
BF_TIME="$(date +%Y%m%d)"
BF_DIR="/mysql_bak/zengbei/$BF_TIME"
CMD="/usr/bin/mysqladmin"
QZ="mysql-bin"
LOG_DIR="/var/lib/mysql"
# 拷贝二进制日志
[ -d $BF_DIR ] || mkdir -p $BF_DIR
$CMD $MY_CONN flush-logs
/bin/cp -p $(ls $LOG_DIR/$QZ.* |awk -v RS="" '{print $(NF-2)}') $BF_DIR
[root@localhost ~]# chmod +x /opt/mysql_bak_*
[root@localhost ~]# crontab -e
0 0 * * 1 /opt/mysql_bak_wanbei.sh //每周一0:00进行完备
0 0 * * 2-7 /opt/mysql_bak_zengbei.sh //每天0:00进行增量备份
[root@localhost ~]# systemctl restart crond