事故:
早几天开发要求查看一下4月24号的数据库,其中有一张表的数据,在4.25号被删除了,现在想了解下那张表的数据。
由于数据库完整备份是7天以内,现在都是5月15号,其他机器上恢复4月24号的数据已经不可能,另外我又想到,完完全全利用二进制日志的备份来做恢复。
在检查二进制日志时,通过mysqlbinlog发现,最原始的binlog已经删除,没有办法从0开始恢复。
类似这样的情况,还真没有好的办法策略,我们的备份策略真的是太烂了,虽然业务量不大,但真是太烂了。
为了应付以后备份数据的可恢复性与灵活性,决定更新备份策略。
新的备份策略思路
检查所有自建数据库数据库备份与二进制日志备份,确认是否依靠数据库备份+二进制日志备份来进行时间点,或者pos点位还原。
(RDS依照RDS的备份策略进行备份,另外可以添加备份到ECS系统)
1、清理mysql二进制日志文件:reset master;
2、设置mysql自动清理7天以前的二进制日志 : expire_logs_days;
3、全库完整备份,数据量比较小,采用mysqldump,
4、定时任务每天凌晨1点开始备份,接着传输到本地
4、二进制日志备份,定时任务每天凌晨2点,将除了当前正在使用的二进制日志备份压缩,
恢复策略
利用最原始的数据库备份先恢复数据库,接着按照备份的二进制日志,按照次序依次恢复至自己想要的数据节点时间的数据。
数据库完整备份
二进制日志选择恢复,可以依据当前要恢复的二进制日志文件pos位置,或者时间。

实验
现有一数据库信息如下:
MariaDB [testdb]> show binary logs ;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 312 |
| mysql-bin.000002 | 464 |
| mysql-bin.000003 | 517 |
| mysql-bin.000004 | 1143 |
| mysql-bin.000005 | 530910 |
+------------------+-----------+
5 rows in set (0.00 sec)
# binlog从mysql-bin.000001开始,并不代表这个二进制日志文件是最原始的,可能清理过binlog
# 备份策略
# 执行reset master;
MariaDB [testdb]> reset master;
Query OK, 0 rows affected (0.01 sec)
MariaDB [testdb]> show binary logs ;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 312 |
+------------------+-----------+
1 row in set (0.00 sec)
# 二进制日志被删除,索引文件内容被初始化。
# 此时数据库正在正常工作,二进制日志文件一直在刷新内容。
MariaDB [testdb]> show binary logs ;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 1268 |
+------------------+-----------+
1 row in set (0.00 sec)
记下来备份数据库,数据库简单备份脚本:
#!/bin/bash
#
BACKDIR=/data/backup/mysql
MYSQLDUMP=/usr/local/mysql/bin/mysqldump
DATEFORMAT=$(date +%Y%m%d%H%M)
LOG=/data/backup/mysql/backup.log
TODAY=`date '+%Y-%m-%d'`
[ -d $BACKDIR/"$TODAY" ] || mkdir -p $BACKDIR/"$TODAY"
[ -f $LOG ] && touch $LOG
find "$BACKDIR" -name "20*" -type d -mtime +7|xargs rm -rf
[ $? -eq 0 ] && echo -e "${DATEFORMAT} Delete 7 days ago backup file success" >> ${LOG} || echo -e "${DATEFORMAT} Delete Old backup file failure" >> ${LOG}
$MYSQLDUMP -uroot -p123456 --routines --triggers --single-transaction --flush-logs --all-database | gzip - | openssl des3 -salt -k 123456 -out ${BACKDIR}/"$TODAY"/mysql-${DATEFORMAT}.sql.gz.des3
[ $? -eq 0 ] && echo -e "${DATEFORMAT} mysqldump database backup success" >> ${LOG} || echo -e "${DATEFORMAT} mysqldump database backup failure" >> ${LOG}
备份数据库文件:
mysql-201705161815.sql.gz.des3
在此备份脚本中,备份所有数据库,备份的同时刷新二进制日志文件。
第一次备份之后的二进制日志情况:
MariaDB [testdb]> show binary logs ;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 1420 |
| mysql-bin.000002 | 365 |
+------------------+-----------+
2 rows in set (0.00 sec)
接着执行二进制日志备份:
[root@node2 backup]# ll binlog_backup/
总用量 12
-rw-r--r-- 1 root root 37 5月 16 18:27 backup.file
-rw-r--r-- 1 root root 131 5月 16 18:27 binlog_backup.log
-rw-r----- 1 root root 486 5月 16 18:27 mysql-bin.000001.gz
接着在次执行多次SQL语句:
MariaDB [testdb]> insert into tb values (12,'a1');
MariaDB [testdb]> insert into tb values (13,'a1');
MariaDB [testdb]> insert into tb values (14,'a3');
MariaDB [testdb]> insert into tb values (15,'a4');
在次备份数据库和二进制日志,备份数据库文件与二进制日志文件:
# 数据库完整备份
mysql-201705161815.sql.gz.des3
mysql-201705161904.sql.gz.des3
# 二进制日志备份
mysql-bin.000001.gz
mysql-bin.000002.gz
此时数据库正在运行,测试错误操作删除数据库:
MariaDB [testdb]> drop database testdb;
现在需要恢复数据,先看看binlog的文件内容:
[root@node2 binlogs]# /usr/local/mysql/bin/mysqlbinlog mysql-bin.000001
/*!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
#170516 17:51:40 server id 2 end_log_pos 248 Start: binlog v 4, server v 10.0.10-MariaDB-log created 170516 17:51:40 at startup
ROLLBACK/*!*/;
BINLOG '
rMsaWQ8CAAAA9AAAAPgAAAAAAAQAMTAuMC4xMC1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACsyxpZEzgNAAgAEgAEBAQEEgAA3AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAEEwQACnhVnw==
'/*!*/;
# at 248
#170516 17:51:40 server id 2 end_log_pos 273 Gtid list []
# at 273
#170516 17:51:40 server id 2 end_log_pos 312 Binlog checkpoint mysql-bin.000001
# at 312
#170516 17:57:02 server id 2 end_log_pos 350 GTID 0-2-1
/*!100001 SET @@session.gtid_domain_id=0*//*!*/;
/*!100001 SET @@session.server_id=2*//*!*/;
/*!100001 SET @@session.gtid_seq_no=1*//*!*/;
BEGIN
/*!*/;
# at 350
#170516 17:57:02 server id 2 end_log_pos 444 Query thread_id=13 exec_time=0 error_code=0
use `testdb`/*!*/;
SET TIMESTAMP=1494928622/*!*/;
SET @@session.pseudo_thread_id=13/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@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=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
insert into tb values (6,'f')
/*!*/;
# at 444
#170516 17:57:02 server id 2 end_log_pos 471 Xid = 1594
COMMIT/*!*/;
# at 471
#170516 17:57:10 server id 2 end_log_pos 509 GTID 0-2-2
/*!100001 SET @@session.gtid_seq_no=2*//*!*/;
BEGIN
/*!*/;
# at 509
#170516 17:57:10 server id 2 end_log_pos 603 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494928630/*!*/;
insert into tb values (7,'g')
/*!*/;
# at 603
#170516 17:57:10 server id 2 end_log_pos 630 Xid = 1595
COMMIT/*!*/;
# at 630
#170516 17:57:14 server id 2 end_log_pos 668 GTID 0-2-3
/*!100001 SET @@session.gtid_seq_no=3*//*!*/;
BEGIN
/*!*/;
# at 668
#170516 17:57:14 server id 2 end_log_pos 762 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494928634/*!*/;
insert into tb values (8,'h')
/*!*/;
截取此次事物查看:
# at 509
#170516 17:57:10 server id 2 end_log_pos 603 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494928630/*!*/;
insert into tb values (7,'g')
/*!*/;
at:表示一次事物开始pos点,
170516 17:57:10 :表示事物开始时间
server id
end_log_pos 603 :表示此次事物终止于此pos点,下次事物就从此点开始记录
Query :事物类型
thread_id :执行事物的线程ID
exec_time=0 :执行事物花费的时间
error_code=0 :执行事物是否有错误
SET TIMESTAMP=1494928630 :事物开始执行的时间戳
insert into tb values (7,'g') :事物要执行的DDL语句
提取备份数据库:
openssl des3 -d -salt -in mysql-201705161815.sql.gz.des3 -out 1815.sql.gz
gunzip 1815.sql.gz
# 获得1815.sql数据库文件
# 恢复数据库
set global sql_log_bin=off; //关闭写入二进制日志
mysql -uroot -p < 1815.sql //恢复第一次备份数据库
use testdb;
select * from tb; //检查数据
MariaDB [testdb]> select * from tb;
+------+------+
| id | name |
+------+------+
......
| 11 | k |
+------+------+
# 我们可以看到数据库数据是到了id 为11
提取备份的二进制日志文件:
/*!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
#170516 18:15:30 server id 2 end_log_pos 248 Start: binlog v 4, server v 10.0.10-MariaDB-log created 170516 18:15:30
BINLOG '
QtEaWQ8CAAAA9AAAAPgAAAAAAAQAMTAuMC4xMC1NYXJpYURCLWxvZwAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA3AAEGggAAAAICAgCAAAACgoKAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAEEwQAbOlnrw==
'/*!*/;
# at 248
#170516 18:15:30 server id 2 end_log_pos 287 Gtid list [0-2-7]
# at 287
#170516 18:15:30 server id 2 end_log_pos 326 Binlog checkpoint mysql-bin.000001
# at 326
#170516 18:15:30 server id 2 end_log_pos 365 Binlog checkpoint mysql-bin.000002
# at 365
#170516 19:02:42 server id 2 end_log_pos 403 GTID 0-2-8
/*!100001 SET @@session.gtid_domain_id=0*//*!*/;
/*!100001 SET @@session.server_id=2*//*!*/;
/*!100001 SET @@session.gtid_seq_no=8*//*!*/;
BEGIN
/*!*/;
# at 403
#170516 19:02:42 server id 2 end_log_pos 499 Query thread_id=13 exec_time=0 error_code=0
use `testdb`/*!*/;
SET TIMESTAMP=1494932562/*!*/;
SET @@session.pseudo_thread_id=13/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@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=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
insert into tb values (12,'a1')
/*!*/;
# at 499
#170516 19:02:42 server id 2 end_log_pos 526 Xid = 1994
COMMIT/*!*/;
# at 526
#170516 19:02:45 server id 2 end_log_pos 564 GTID 0-2-9
/*!100001 SET @@session.gtid_seq_no=9*//*!*/;
BEGIN
/*!*/;
# at 564
#170516 19:02:45 server id 2 end_log_pos 660 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494932565/*!*/;
insert into tb values (13,'a1')
/*!*/;
# at 660
#170516 19:02:45 server id 2 end_log_pos 687 Xid = 1995
COMMIT/*!*/;
# at 687
#170516 19:02:50 server id 2 end_log_pos 725 GTID 0-2-10
/*!100001 SET @@session.gtid_seq_no=10*//*!*/;
BEGIN
/*!*/;
# at 725
#170516 19:02:50 server id 2 end_log_pos 821 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494932570/*!*/;
insert into tb values (14,'a3')
/*!*/;
# at 821
#170516 19:02:50 server id 2 end_log_pos 848 Xid = 1996
COMMIT/*!*/;
# at 848
#170516 19:02:54 server id 2 end_log_pos 886 GTID 0-2-11
/*!100001 SET @@session.gtid_seq_no=11*//*!*/;
BEGIN
/*!*/;
# at 886
#170516 19:02:54 server id 2 end_log_pos 982 Query thread_id=13 exec_time=0 error_code=0
SET TIMESTAMP=1494932574/*!*/;
insert into tb values (15,'a4')
/*!*/;
# at 982
#170516 19:02:54 server id 2 end_log_pos 1009 Xid = 1997
COMMIT/*!*/;
# at 1009
#170516 19:04:53 server id 2 end_log_pos 1047 GTID 0-2-12
/*!100001 SET @@session.gtid_seq_no=12*//*!*/;
# at 1047
#170516 19:04:53 server id 2 end_log_pos 1118 Query thread_id=15 exec_time=0 error_code=0
SET TIMESTAMP=1494932693/*!*/;
FLUSH TABLES
/*!*/;
# at 1118
#170516 19:04:53 server id 2 end_log_pos 1161 Rotate to mysql-bin.000003 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*/;
根据此二进制日志文件恢复方式:
1、按照时间恢复:
mysqlbinlog mysql-bin.000002 --stop-date="2017-05-16 19:02:45" | mysql -uroot -p
# 根据上面的二进制日志,可以查看到170516 19:02:45 此时间之前是有做一笔插入id为12数据的动作,是恢复在此时间之前。
# 检查数据库
MariaDB [testdb]> select * from tb;
+------+------+
| id | name |
+------+------+
......
| 11 | k |
| 12 | a1 |
+------+------+
#检查到数据库已经回复至id为12位置。
2、按照位置点恢复
mysqlbinlog mysql-bin.000002 --start-position="564" --stop-position="821" | mysql -uroot -p
# 根据设置pos位置点,比较如上二进制日志文件可以得出,是恢复insert into tb values (13,'a1')此SQL语句
# 检查数据库
MariaDB [testdb]> select * from tb;
+------+------+
| id | name |
+------+------+
......
| 11 | k |
| 12 | a1 |
| 13 | a1 |
+------+------+
3、二进制日志导出文件,并修改恢复,
测试前先删除数据库 > drop database testdb;
# 先恢复数据库初始
mysql -u root -p < 1815.sql
# 根据二进制日志文件,截取自己需要的信息并导出成文件,接着恢复
mysqlbinlog mysql-bin.000002 --stop-position="1009" > binlog.sql
# 截取至1009pos位置的信息,进行恢复。(当然也可以利用vim编辑器进行修改)
mysql -u root -p < binlog.sql
# 调整过的二进制日志内容附加到之前恢复的数据中
检查数据库
MariaDB [testdb]> select * from tb;
+------+------+
| id | name |
+------+------+
......
| 11 | k |
| 12 | a1 |
| 13 | a1 |
| 14 | a3 |
| 15 | a4 |
+------+------+
# 结果如我们预期一模一样。
有类似这样的备份策略,就可以恢复至某时间点的数据,后续要用到某时间点数据时,也可以方便恢复调用。
1、每天备份数据库,二进制日志文件,这样当天的内容没有备份,假如数据量比较大,这样一天丢失的数据也比较达,可以适当调整二进制日志文件备份策略,利用定时任务刷新二进制日志,接着每两小时备份一次。
2、数据量大了还是需要另外的备份工具,mysqldump,时间太长。
网友评论