MySQL增量备份与恢复

一   MySQL增量备份概念

使用mysqldump进行完全备份,备份的数据中有重复数据,备份时间与恢复时间过长。而增量备份就是备份自上一次备份之后增加或改变的文件或内容。

增量备份的特点:

没有重复数据,备份量不大,时间短

恢复麻烦:需要上次完全备份及完全备份之后所有的增量备份才能恢复,而且要对所有增量备份进行逐个反推恢复。

MySQL没有提供直接的增量备份办法,可以通过MySQL提供的二进制日志(binary logs(binlog))间接实现增量备份。

MySQL二进制日志对备份的意义:

二进制日志保存了所有更新或者可能更新数据库的操作。

二进制日志在启动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 
vim /etc/my.cnf
server-id=1
log-bin=mysql-bin  // mysql-bin前缀名

保存退出,重启mariadb 

 

然后查看 /var/lib/mysql/ 会出现两个文件  mysql-bin.index  mysql-bin.00001

方法二:使用mysqld --log-bin=文件存放路径/文件前缀 重新启动mysqld服务

每周选择服务器负载较轻的时间段,或者用户访问较少的时间段进行备份。(一次性的)

二、MySQL增量恢复

应用场景

  1. 人为的SQL语句破坏了数据库
  2. 在进行下一次全备之前发生系统故障导致数据库数据丢失
  3. 在主从架构中,主库数据发生了故障
  4. 一般的恢复:备份的二进制日志内容全部恢复

增量恢复的方法

格式:mysqlbinlog [--no-defaults] 增量备份文件 | mysql -u用户名 -p密码

 

  1. 基于时间点的恢复:便于跳过某个发生错误的时间点实现数据恢复

格式:从日志开头截止到某个时间点的恢复:

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密码

 

  1. 基于位置的恢复:可能在同一时间点既有错误的操作也有正确的操作,基于位置进行恢复更加精准

格式:

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

三、制定企业备份策略的思路

  1. 确定当前mysql 是处于哪种表类型下工作的,它们支持事物处理还是非事物的,因为我们需要根据不同的特点来做一些设置。
  2. 要选择备份的形式是完全备份还是增量备份,它们各有优缺点。
  3. 为了保证恢复的完整性,我们得开启binary log功能,同时binlog给恢复工作也带来了很大的灵活性,可以基于时间点或是位置进行恢复。考虑到数据库性能,我们可以将binlog文件保存到其他安全的硬盘中。
  4. 正如最初所提到的,备份操作和应用服务同时运行,这样就十分消耗系统资源了,会导致数据库服务性能下降,这就要求我们选择一个合适的时间(比如在应用负担很小的时候)再来进行备份操作。
  5. 不是备份完就万事大吉,我们还得确认备份是否可用,所以之后的恢复测试是完全有必要的。

 

l 根据数据更新频繁,则应该较为频繁的备份

l 数据重要,则在有适当更新时进行备份

l 在数据库压力小的时段进行备份,如一周一次完全备份,然后每天进行增量备份

l 中小公司,全备一般可一天一次

l 大公司可每周进行一次全备,每天进行一次增量备份

l 尽量为企业实现主从复制架构

四、MySQL企业备份案例

需求描述:

北京移电通信公司的用户信息数据库为client,用户资费数据表为user_info

请为该公司每周进行完全备份

每天为该公司进行增量备份

新增加的用户信息如表所示

 

安装mysqlyum方式)

mysqladmin -uroot -p123456 flush-logs //切日志
[root@localhost ~]# vim /etc/my.cnf
[client]
default-character-set = utf8
 
[mysqld]
default-character-set = utf8
[root@localhost ~]# /usr/local/mysql/bin/mysqld.sh start

添加数据库、表,录入数据

[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));
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 ~]# mysqlbinlog --no-defaults --base64-output=decode-rows -v /mysql_bak/mysql-bin.000002//查看新操作的日志记录
[root@localhost ~]# cp -p /usr/local/mysql/data/mysql-bin.000002 /mysql_bak/

 

模拟误操作删除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 Querythread_id=7exec_time=0error_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 Querythread_id=7exec_time=0error_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    //--stop-position='345' 到什么地方结束
[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
00**1/opt/mysql_bak_wanbei.sh//每周一0:00进行完备
00**2-7/opt/mysql_bak_zengbei.sh//每天0:00进行增量备份