1. 全量备份与增量备份理论基础
1.1 全量备份
全量数据就是数据库中的所有数据,全量备份就是把数据库中所有的数据进行备份。
1.2 增量备份
增量数据就是从上次全量备份之后,到下一次全备之前时间段更新的新数据。对于 MySQL 来说,binlog 日志就是 MySQL 的增量数据。
1.3 按天全备备份:每天零点做一次全备
优点:恢复时间短,维护成本低;
缺点:占用空间多,占用系统资源多,经常锁表影响用户体验。
1.4按周全备备份:每周六零点做一次全备
优点:占用空间小(一周一个所有数据的副本),占用系统资源少,无需经常锁表,用户体验好。
缺点:维护成本高,恢复数据麻烦,耗时长。
提示:以上优缺点都是在一般情况下,排除在从库做备份的情况。
1.5 企业场景全量和增量备份的做法
① 中小公司,全量一般是每天一次,业务流量低估执行全备,备份时会锁表。
② 单台数据库(没有主从同步)的增量一般用 rsync 把所有的 binlog 备份到远程服务器;尽量做主从复制保证数据不丢失。
③ 大公司周备,每周六 0 点做一次全量备份,周日到下周六之前都是增量。
优点:节省备份时间,减小备份压力。
缺点:增量的 binlog 文件副本太多,还原会很麻烦。
④ 一主多从,会有一个从库做备份,延迟同步。
1.6 MySQL 的 mysqldump 备份什么时候能派上用场
① 迁移或者升级数据库时;
② 增加从库的时候;
③ 因为硬件问题或特殊异常情况,主库或从库宕机,主从可互相切换,这种情况下不需要备份。
④ 人为的 DDL,DML 语句误操作,导致误删数据,主从库都会执行,此时就需要备份。
⑤ 跨机房灾备,需要将全量备份拷贝到异地容灾环境。
1.7 什么情况下需要增量恢复
我们在生产环境中一般常用一主多从的数据库架构,常见的备份方案是在某一个不对外服务的从库上开启 binlog,然后实施定时全备和时时增量备份。
增量恢复:利用二进制日志和全备进行的恢复数据的过程就是增量恢复。
① 主库或从库宕机(硬件损坏)是否需要增量恢复?
答案:不需要增量恢复,只需要把其中一个同步最快的从库切换为主库即可。
② 人为操作数据库 SQL 语句破坏主库是否需要增量恢复?
答案:在数据库主库内部命令行误操作,会导致所有的数据库(包括主从库)数据丢失,例如在主库执行了 drop database test; 这样的删除语句,所有的从库也会执行这个语句,从而导致所有的数据库上的 test 库数据丢失,这样的场景是需要增量恢复的。
③ 只有一个主库是否需要增量恢复?
答案:如果公司只有一个主库的情况,首先应该做定时全量备份(一天一次)及增量备份(每隔一到十分钟对 binlog 日志做切割然后备份到其他服务器上或本地其他的硬盘里)或者写到网络文件系统(备份服务器)里。
如果不允许数据丢失,最好的办法是做从库,通过 drbd(基于磁盘快)的同步。
小结:一般由人为(或程序)逻辑的方式在数据库执行的 SQL 语句等操作,才需要增量恢复,因为此时所有的从库上也执行了误操作语句。
1.8 MySQL 增量恢复必备条件
① 开启 MySQL 的记录 binlog 日志功能:
[root@master ~]# grep log-bin /etc/my.cnf
log-bin=mysql-bin
提示:主库和备份的从库都要开启 binlog 记录功能。
小结:增量恢复的条件:
存在一份全备加上全备之后的时刻到出问题时刻的所有增量 binlog 文件备份。
② 存在 MySQL 数据库全备:
生产环境 mysqldump 备份命令:略
在凌晨某一时刻进行数据库全备(生产场景一般通过定时任务每日凌晨执行)。
2. MySQL 人为误操作丢失数据场景模拟
2.1 创建 student 表并插入数据做全备
[root@master ~]# mysql -uroot -p123456
mysql> use oldboy
Database changed
mysql> CREATE TABLE `student` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` char(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
INSERT INTO `student` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka'),(6,'kobe'),(7,'james'),(8,'iverson'),(9,'embid');
mysql> show tables;
| Tables_in_oldboy |
| student |
mysql> select * from student;
| id | name |
| 1 | oldboy |
| 2 | oldgirl |
| 3 | inca |
| 4 | zuma |
| 5 | kaka |
| 6 | kobe |
| 7 | james |
| 8 | iverson |
| 9 | embid |
[root@master ~]# date -s '2018/05/11' # 修改时间为 0 点。
Fri May 11 00:00:00 CST 2018
[root@master ~]# mkdir /server/backup # 创建备份的目录。
[root@master ~]# mysqldump -uroot -p123456 --master-data=2 -F -B oldboy|gzip >/server/backup/bak_$(date +%F).sql.gz # 为 oldboy 数据库做全备。
2.2 模拟插入数据
[root@master ~]# mysql -uroot -p123456 # 登陆数据库写数据。
mysql> use oldboy
mysql> desc student;
| Field | Type | Null | Key | Default | Extra |
| id | int(4) | NO | PRI | NULL | auto_increment |
| name | char(20) | NO | | NULL | |
mysql> insert into student(name) values('oldboy101');
mysql> insert into student(name) values('oldboy102');
mysql> select * from student; # 查看上面插入的两条数据。
| 10 | oldboy101 |
| 11 | oldboy102 |
2.3 模拟用户破环数据
mysql> show databases;
| oldboy |
mysql> drop database oldboy; # 删除 oldboy 库。
mysql> show databases; # oldboy 库已经不存在。
3. 发现故障并排查原因
数据库出问题 10 分钟后,公司的网站运营人员报网站故障,联系运维人员解决。此时,DBA 人员或开发人员通过查看网站报错(或者查看后台日志),可以看到连不上 oldboy 库的提示,然后通过登陆数据库排查发现 oldboy 库不存在了,被同事误删了。
提示:通过对数据库权限的严格管理及审核可避免此类误操作问题的发生。
4. 增量恢复过程
4.1 恢复丢失数据前提
通过防火墙禁止 web 等应用向主库写数据或者锁表,让主库暂停时停止更新,然后再进行恢复(若允许停库最好)。
4.2 检查全备及 binlog 日志
root@master ~]# ll /server/backup/ # 检查全备。
-rw-r--r-- 1 root root 913 May 11 00:07 bak_2018-05-11.sql.gz
[root@master ~]# ll /application/mysql/data/ # 查看 binlog 日志。
-rw-rw---- 1 mysql mysql 1654 May 11 00:04 mysql-bin.000005
-rw-rw---- 1 mysql mysql 150 May 11 00:05 mysql-bin.000006
-rw-rw---- 1 mysql mysql 150 May 11 00:07 mysql-bin.000007
-rw-rw---- 1 mysql mysql 662 May 11 00:19 mysql-bin.000008
-rw-rw---- 1 mysql mysql 152 May 11 00:07 mysql-bin.index
[root@master ~]# cd /server/backup/
[root@master backup]# ll
-rw-r--r-- 1 root root 913 May 11 00:07 bak_2018-05-11.sql.gz
[root@master backup]# gzip -d bak_2018-05-11.sql.gz
[root@master backup]# grep -i "change" bak_2018-05-11.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000008', MASTER_LOG_POS=107;
4.3 立即刷新并备份出增量 binlog 数据
[root@master backup]# mysqladmin -uroot -p123456 flush-logs # 刷新 binlog 。
[root@master backup]# ll /application/mysql/data/ # 查看。
-rw-rw---- 1 mysql mysql 705 May 11 00:42 mysql-bin.000008 # 需要恢复的 binlog(误操作语句)。
-rw-rw---- 1 mysql mysql 107 May 11 00:42 mysql-bin.000009 # 插入新数据的 binlog(人为误操作后用户插入其他数据)。
[root@master backup]# cp /application/mysql/data/mysql-bin.000008 /server/backup/ # 备份增量(全备以后的含有误操作语句的增量)。
[root@master backup]# ll /server/backup/
-rw-r--r-- 1 root root 2284 May 11 00:07 bak_2018-05-11.sql
-rw-r----- 1 root root 705 May 11 00:46 mysql-bin.000008
[root@master backup]# mysqlbinlog -d oldboy mysql-bin.000008
[root@master backup]# mysqlbinlog -d oldboy mysql-bin.000008 >bin.sql
[root@master backup]# vi bin.sql # 找到 drop database oldboy; 误操作语句并把它删掉。
[root@master backup]# ll # 把下面的两个恢复进去即可。
-rw-r--r-- 1 root root 2284 May 11 00:07 bak_2018-05-11.sql # 全量。
-rw-r--r-- 1 root root 2352 May 11 00:50 bin.sql # 清除误操作语句的增量数据。
4.4 问题:恢复数据的语句会记录到新的 binlog 文件中
mysql> show variables like '%log_bin%';
| Variable_name | Value |
| log_bin | ON |
| log_bin_trust_function_creators | OFF |
| sql_log_bin | ON |
# 该参数改为 off 就可以不记录恢复过程,但是用户写入数据也无法记录了。因为此处没有用户往数据库写入数据,企业场景会通过防火墙不让用户写入或者让用户只读。
4.5 开始恢复数据
[root@master backup]# mysql -uroot -p123456 <bak_2018-05-11.sql # 恢复全量备份。
[root@master backup]# mysql -uroot -p123456 oldboy <bin.sql # 恢复增量备份。
[root@master backup]# mysql -uroot -p123456 # 查看数据恢复结果。
mysql> show databases;
| oldboy |
mysql> use oldboy
mysql> select * from student;
| 1 | oldboy |
| 2 | oldgirl |
| 3 | inca |
| 4 | zuma |
| 5 | kaka |
| 6 | kobe |
| 7 | james |
| 8 | iverson |
| 9 | embid |
| 10 | oldboy101 |
| 11 | oldboy102 |
5. 案例总结
5.1 增量恢复小结
① 人为 SQL 造成的误操作;
② 全备和增量;
③ 恢复时建议对外停止更新;
④ 恢复全量,然后把增量日志中有问题的 SQL 语句删除,恢复到数据库。
5.2 增量恢复核心思想
① 流程制度控制,防止问题发生。如果不做流程制度控制,就会面临停止服务和丢失数据之间的取舍;
② 在业务上对一些信息做监控,黑名单,白名单机制。(通过流程制度控制不加 while 语句不能执行等);
③ 根据业务需求容忍度,制定一个可量化的目标,根据需求来选择停库或锁表或者容忍丢失部分数据。