MySQL增量备份与恢复
一、MySQL增量备份概念
使用mysqldump进行完全备份,备份的数据中有重复数据,备份时间与恢复时间过长。而增量备份就是备份自上一次备份之后增加或改变的文件或内容。
增量备份的特点:
没有重复数据,备份量不大,时间短。
恢复麻烦:需要上次完全备份及完全备份之后所有的增量备份才能恢复,而且要对所有增量备份进行逐个反推恢复。
MySQL 没有提供直接的增量备份办法,可以通过 MySQL提供的二进制日志(binarylogs(binlog))间接实现增量备份。
MySQL 二进制日志对备份的意义:
二进制日志保存了所有更新或者可能更新数据库的操作。
二进制日志在启动 MySQL 服务器后开始记录,并在文件达到max binlogIsize所设置的大小或者接收到 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,$OY /etc/my.cnf
server-id=1
log-bin=mysql-bin
方法二:使用 mysqld-log-bin=文件存放路径/文件前缀 重新启动 mysqld 服务,每周选择服务器负载较轻的时间段,或者用户访问较少的时间段进行备份。
二、MySQL增量恢复
应用场景:
1、人为的SQL 语句破坏了数据库
2、在进行下一次全备之前发生系统故障导致数据库数据丢失
3、在主从架构中,主库数据发生了故障
增量恢复的方法:
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密码
三、制定企业备份策略的思路
1、确定当前 mysql是处于哪种表类型下工作的,它们支持事物处理还是非事物的,因为我们需要根据不同的特点来做一些设置。
2、要选择备份的形式是完全备份还是增量备份,它们各有优缺点。
3、为了保证恢复的完整性,我们得开启 binarylog功能,同时binlog给恢复工作也带来了很大的灵活性,可以基于时间点或是位置进行恢复。考虑到数据库性能,我们可以将binlog_文件保存到其他安全的硬盘中。
4、正如最初所提到的,备份操作和应用服务同时运行,这样就十分消耗系统资源了,会导致数据库服务性能下降,这就要求我们选择一个合适的时间(比如在应用负担很小的时候)再来进行备份操作。
5、不是备份完就万事大吉,我们还得确认备份是否可用,所以之后的恢复测试是完全有必要的。
根据数据更新频繁,则应该较为频繁的备份
数据重要,则在有适当更新时进行备份
在数据库压力小的时段进行备份,如一周一次完全备份,然后每天进行增量备份
中小公司,全备一般可一天一次
大公司可每周进行一次全备,每天进行一次增量备份
尽量为企业实现主从复制架构
四、案例演示
要进行MySQL的增量备份,首先要开启MySQL二进制日志功能
[root@localhost ~]# vim /etc/my.cnf
[mysqld]
server-id=1
log-bin=mysql-bin
[root@localhost ~]# systemctl restart mariadb
[root@localhost ~]# ls /var/lib/mysql/ //查看一下
[root@localhost ~]# mysqladmin -uroot -p123 flush-logs // 切一下日志,开始使用第二个日志
1、创建数据库、表、录入数据
MariaDB [(none)]> create database lty;
Query OK, 1 row affected (0.01 sec)
MariaDB [(none)]> use lty
Database changed
MariaDB [lty]> create table user_info(身份证 char(20) not null,姓名 char(20) not null,D号 char(10) not null,资费 int(10));
Query OK, 0 rows affected (0.01 sec)
MariaDB [lty]> desc user_info;
+-------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+-------+
| 身份证 | char(20) | NO | | NULL | |
| 姓名 | char(20) | NO | | NULL | |
| 性别 | char(4) | YES | | NULL | |
| 用户ID号 | char(10) | NO | | NULL | |
| 资费 | int(10) | YES | | NULL | |
+-------------+----------+------+-----+---------+-------+
5 rows in set (0.00 sec)
MariaDB [lty]> insert into user_info values('000000006','张三','男','016','10');
Query OK, 1 row affected (0.01 sec)
MariaDB [lty]> insert into user_info values('000000006','李四','女','017','91');
Query OK, 1 row affected (0.01 sec)
MariaDB [lty]> insert into user_info values('000000006','王五','女','018','23');
Query OK, 1 row affected (0.01 sec)
MariaDB [lty]> select * from user_info;
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
+-----------+--------+--------+-------------+--------+
3 rows in set (0.00 sec)
2、创建一个文件夹用来做备份
[root@localhost ~]# mkdir /mysql_bak
3、对现有的三个人做一个完整备份
[root@localhost ~]# mysqldump -uroot -p123 lty user_info >/mysql_bak/lty_user_info-$(date +%F).sql // 对表进行完整备份
[root@localhost ~]# mysqldump -uroot -p123 --databases lty > /mysql_bak/lty-$(date +%F).sql //对库进行完整备份
[root@localhost ~]# ls /mysql_bak/ //查看
lty-2019-10-14.sql lty_user_info-2019-10-14.sql
4、切一个日志
[root@localhost ~]# mysqladmin -uroot -p123 flush-logs
5、再插入两条记录
MariaDB [lty]> insert into user_info values('000000009','赵六','男','019','37');
Query OK, 1 row affected (0.01 sec)
MariaDB [lty]> insert into user_info values('000000010','孙七','男','020','36');
Query OK, 1 row affected (0.00 sec)
6、再切一个日志,生成了4号日志,但是我要用的日志是3号日志
[root@localhost ~]# mysqladmin -uroot -p123 flush-logs
[root@localhost ~]# ls /var/lib/mysql/
aria_log.00000001 client ib_logfile0 mysql mysql-bin.000003 mysql.sock
aria_log_control crushlinux ib_logfile1 mysql-bin.000001 mysql-bin.000004 performance_schema
auth ibdata1 lty mysql-bin.000002 mysql-bin.index test
7、实验文档里用的是2好日志,拿走3号改名03
[root@localhost ~]# cp /var/lib/mysql/mysql-bin.000003 /mysql_bak/mysql-bin.000002
8、作分析:
[root@localhost ~]# mysqlbinlog --no-defaults /mysql_bak/mysql-bin.000002
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#191014 15:02:53 server id 1 end_log_pos 245 Start: binlog v 4, server v 5.5.41-Mari91014 15:02:53
BINLOG '
nR2kXQ8BAAAA8QAAAPUAAAAAAAQANS41LjQxLU1hcmlhREItbG9nAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAx8QIRg==
'/*!*/;
# at 245
#191014 15:04:21 server id 1 end_log_pos 312 Query thread_id=4 exec_time=0
SET TIMESTAMP=1571036661/*!*/;
SET @@session.pseudo_thread_id=4/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checutocommit=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.colla*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 312
#191014 15:04:21 server id 1 end_log_pos 441 Query thread_id=4 exec_time=0
use `lty`/*!*/;
SET TIMESTAMP=1571036661/*!*/;
insert into user_info values('000000009','赵六','男','019','37')
/*!*/;
# at 441
#191014 15:04:21 server id 1 end_log_pos 468 Xid = 80
COMMIT/*!*/;
# at 468
#191014 15:04:52 server id 1 end_log_pos 535 Query thread_id=4 exec_time=0
SET TIMESTAMP=1571036692/*!*/;
BEGIN
/*!*/;
# at 535
#191014 15:04:52 server id 1 end_log_pos 664 Query thread_id=4 exec_time=0
SET TIMESTAMP=1571036692/*!*/;
insert into user_info values('000000010','孙七','男','020','36')
/*!*/;
# at 664
#191014 15:04:52 server id 1 end_log_pos 691 Xid = 81
COMMIT/*!*/;
# at 691
#191014 15:06:56 server id 1 end_log_pos 734 Rotate to mysql-bin.000004 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
其中有后来插入的两条信息记录
9、模拟误操作删除user_info表,并查看
[root@localhost ~]# mysql -uroot -p123 -e 'drop table lty.user_info;'
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
ERROR 1146 (42S02) at line 1: Table 'lty.user_info' doesn't exist
10、先恢复完整备份
[root@localhost ~]# mysql -uroot -p123 lty < /mysql_bak/lty_user_info-2019-10-14.sql
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
+-----------+--------+--------+-------------+--------+
完整备份里只有三个人的信息,剩下两个人的信息要靠增量的二进制日志来进行恢复
11、恢复增量备份:
[root@localhost ~]# mysqlbinlog --no-defaults /mysql_bak/mysql-bin.000002 | mysql -u root -p123 //将日志中的所有的语句都执行了一遍
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
| 000000009 | 赵六 | 男 | 019 | 37 |
| 000000010 | 孙七 | 男 | 020 | 36 |
+-----------+--------+--------+-------------+--------+
数据信息完全恢复了。
试一下有条件的增量恢复二进制日志:
只恢复到有赵六的数据:
[root@localhost ~]# mysql -uroot -p123 -e 'drop table lty.user_info;'
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
ERROR 1146 (42S02) at line 1: Table 'lty.user_info' doesn't exist
[root@localhost ~]# mysql -uroot -p123 lty < /mysql_bak/lty_user_info-2019-10-14.sql //先恢复完整备份
[root@localhost ~]# mysqlbinlog --no-defaults --stop-datetime='2019-10-14 15:04:35' /my.000002 | mysql -u root -p123
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
| 000000009 | 赵六 | 男 | 019 | 37 |
+-----------+--------+--------+-------------+--------+
只恢复到有孙七的数据:
[root@localhost ~]# mysql -uroot -p123 -e 'drop table lty.user_info;'
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
ERROR 1146 (42S02) at line 1: Table 'lty.user_info' doesn't exist
[root@localhost ~]# mysql -uroot -p123 lty < /mysql_bak/lty_user_info-2019-10-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults --start-datetime='2019-10-14 15:04:35' /mysql_bak/mysql-bin.000002 | mysql -u root -p123
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
| 000000010 | 孙七 | 男 | 020 | 36 |
+-----------+--------+--------+-------------+--------+
基于位置控制恢复:
[root@localhost ~]# mysql -uroot -p123 -e 'drop table lty.user_info;'
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
ERROR 1146 (42S02) at line 1: Table 'lty.user_info' doesn't exist
[root@localhost ~]# mysql -uroot -p123 lty < /mysql_bak/lty_user_info-2019-10-14.sql
[root@localhost ~]# mysqlbinlog --no-defaults --stop-position='468' /mysql_bak/mysql-bi-u root -p123
[root@localhost ~]# mysql -uroot -p123 -e 'select * from lty.user_info;'
+-----------+--------+--------+-------------+--------+
| 身份证 | 姓名 | 性别 | 用户ID号 | 资费 |
+-----------+--------+--------+-------------+--------+
| 000000006 | 张三 | 男 | 016 | 10 |
| 000000006 | 李四 | 女 | 017 | 91 |
| 000000006 | 王五 | 女 | 018 | 23 |
| 000000009 | 赵六 | 男 | 019 | 37 |
+-----------+--------+--------+-------------+--------+
五、企业数据库备份脚本
1、完整备份脚本
[root@localhost ~]# vim /opt/mysql_bak_wanbei.sh
#!/bin/bash
# MySQL数据库备份脚本
# 设置登录变量
MY_USER="root"
MY_PASS="123"
MY_HOST="192.168.200.111"
MY_CONN="-u$MY_USER -p$MY_PASS -h$MY_HOST"
# 设置备份的数据库(或表)
MY_DB="lty"
# 定义备份路径、工具、时间、文件名
BF_DIR="/mysql_bak/wanbei"
BF_CMD="/usr/bin/mysqldump"
BF_TIME=$(date +%Y%m%d-%H%M)
NAME="$MY_DB1-$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
2、增量备份
[root@localhost ~]# vim /opt/mysql_bak_zengbei.sh
#!/bin/bash
# MySQL数据库备份脚本
# 设置登录变量
MY_USER="root"
MY_PASS="123"
MY_HOST="192.168.200.111"
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 0 * * 2-7 /opt/mysql_bak_zengbei.sh //每周二至周天零点进行增量备份