MySQL-binlog2sql
:非主从实时同步+恢复误删数据 针对于DBA
或开发人员,有时会误删或者误更新数据,如果是线上环境并且影响较大,就需要能快速回滚。
传统恢复方法是利用备份重搭实例,再应用去除错误sql
后的binlog
来恢复数据。此法费时费力,甚至需要停机维护,并不适合快速回滚。也有团队利用LVM
快照来缩短恢复时间,但快照的缺点是会影响mysql的性能。现在有不少好用而且效率又高的开源闪回工具如【binlog2sql、mysqlbinlog_flashback
】,这些工具在工作中给DBA
减轻了不少痛苦,以下针对binlog2sql
的使用进行实践演练。
binlog
生成标准SQL
,带来的衍生功能(sql
可直接执行的那种~)binlog
,同步到其它数据库
mysql234
】mysql236
】binlog
所有数据到目标数据库binlog2sql
主要做紧急恢复来使用
mysql234
】binlog
误删数据-B
选项
纯sql语句
反向解析,即:
insert
解析为delete
delete
解析为insert
update
不会改变原理:主要是对于
delete
操作,从binlog
取出delete
信息,生成insert
的回滚语句。对于insert
操作,回滚SQL
是delete
。对于update
操作,回滚sql
应该交换SET
和WHERE
的值。
MySQL
参见:MySQL安装部署启动
MySQL
配置针对于源数据库
cat my.cnf [mysqld] server_id = 1 log_bin = /var/log/mysql/mysql-bin.log max_binlog_size = 1G binlog_format = row binlog_row_image = full(默认)
binlog2sql
官网下载:戳我~
百度云链接:戳我~ 提取码:peng
推荐,百度云打包的文件是经我测试过的,不用担心版本问题,下载上传后可直接执行后面的解压安装命令
python-pip
PyMySQL
python-mysql-replication
wheel argparse
mkdir /opt/binlog2sql/packages && cd /opt/binlog2sql/packages # 上传包 # 解压到上层 unzip binlog2sql.zip -d /binlog cd /binlog tar xf pip-10.0.1.tar.gz tar xf PyMySQL-0.8.0.tar.gz tar xf wheel-0.31.0.tar.gz unzip binlog2sql-master.zip unzip python-mysql-replication-master.zip rm -f *.gz *.zip # 查看目录 [root@web2 ~]# ll total 20K drwxr-xr-x 5 root root 4.0K Jan 4 2018 binlog2sql-master drwxrwxrwx 4 root root 4.0K Apr 20 2018 pip-10.0.1 drwxr-xr-x 4 501 games 4.0K Dec 20 2017 PyMySQL-0.8.0 drwxr-xr-x 7 root root 4.0K Mar 1 2018 python-mysql-replication-master drwxr-xr-x 4 2000 2000 4.0K Apr 2 2018 wheel-0.31.0
若报错,则安装
python3
:yum install -y python3
,将下方的python替换为python3
# 安装依赖环境 cd PyMySQL-0.8.0/ python setup.py install cd ../wheel-0.31.0/ python setup.py install cd ../python-mysql-replication-master/ python setup.py install # 检测依赖安装,already表示已安装 cd ../pip-10.0.1/ pip freeze > requirements.txt pip install -r requirements.txt
方便一键调用,不用再单独执行
python+py
的路径了~直接可以用
binlog2sql
来代替python /opt/binlog2sql/binlog2sql-master/binlog2sql/binlog2sql.py
这条命令
echo "alias binlog2sql='python /opt/binlog2sql/binlog2sql-master/binlog2sql/binlog2sql.py'" >> ~/.bashrc source ~/.bashrc
CREATE DATABASE `peng` DEFAULT CHARACTER SET utf8mb4; USE peng; CREATE TABLE `binlog_test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4;
记录插入数据的时间,精确到秒,此时是【
2021-11-19 15:20:06
】PS:可提前几秒
INSERT INTO `peng`.`binlog_test` (`id`, `name`) VALUES (1, '插入数据1'); INSERT INTO `peng`.`binlog_test` (`id`, `name`) VALUES (1, '插入数据2'); INSERT INTO `peng`.`binlog_test` (`id`, `name`) VALUES (1, '插入数据3');
mysql> SELECT * FROM `peng`.`binlog_test`; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | | 2 | 插入数据2 | | 3 | 插入数据3 | +----+---------------+ 3 rows in set (0.00 sec)
模拟开发人员误删除数据,此时时间是【
2021-11-19 15:32:14
】左右
PS
:若误删除数据时间记不清楚,恢复时可在此基础上往后延迟几秒或几分,若数据量比较多,时间间隔越小,排查起来也越快!
删除选中的两条记录
删除后,发现数据只剩一条
[root@myslq ~]# mysql234 mysql> select * from peng.binlog_test; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | +----+---------------+ 1 row in set (0.00 sec)
场景了解参见:场景介绍
导出后会自动优化为纯
sql
语句,无没用的部分,可直接在数据库执行的那种~
导出前询问误删除数据的时间,精确到秒,基于上面的例子,记不清楚的话往后延迟几秒:【
2021-11-19 15:33:00
】导出后可见,插入的三条和删除的两条都有记录,且后面带有
position
(位置点)、操作的时间记录
binlog2sql -h 172.23.0.234 -P 3306 -u root -peHu2016 -d peng -t binlog_test --start-file='mysql-bin.000006' --start-datetime='2021-11-19 15:20:00' --stop-datetime='2021-11-19 15:23:00' > binlog1.sql
[root@web2 ~]# cat binlog1.sql INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 4741 end 4925 time 2021-11-19 15:20:31 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 4956 end 5140 time 2021-11-19 15:20:38 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 5171 end 5355 time 2021-11-19 15:20:44 DELETE FROM `peng`.`binlog_test` WHERE `id`=2 AND `name`='插入数据2' LIMIT 1; #start 5386 end 5570 time 2021-11-19 15:32:01 DELETE FROM `peng`.`binlog_test` WHERE `id`=3 AND `name`='插入数据3' LIMIT 1; #start 5601 end 5785 time 2021-11-19 15:32:01
检查需要对应的
posistion
位置点、数据信息、时间点,确认无误后,方可导入至另一台数据库另一台数据库要有对应结构、同名的库、表,或另一台已经导入过此数据库的全量数据(前提是上面插入的数据是在导入全量之后插入的)
PS:若数据量大,则可直接库外导入
sql
,或利用数据库工具来导入在另一台导入上面的
sql
,发现与源数据库的数据是相同的,成功~
INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 4741 end 4925 time 2021-11-19 15:20:31 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 4956 end 5140 time 2021-11-19 15:20:38 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 5171 end 5355 time 2021-11-19 15:20:44 DELETE FROM `peng`.`binlog_test` WHERE `id`=2 AND `name`='插入数据2' LIMIT 1; #start 5386 end 5570 time 2021-11-19 15:32:01 DELETE FROM `peng`.`binlog_test` WHERE `id`=3 AND `name`='插入数据3' LIMIT 1; #start 5601 end 5785 time 2021-11-19 15:32:01
[root@web2 binlog2sql]# mysql236 mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 4741 end 4925 time 2021-11-19 15:20:31 Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 4956 end 5140 time 2021-11-19 15:20:38 Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 5171 end 5355 time 2021-11-19 15:20:44 Query OK, 1 row affected (0.00 sec) mysql> DELETE FROM `peng`.`binlog_test` WHERE `id`=2 AND `name`='插入数据2' LIMIT 1; #start 5386 end 5570 time 2021-11-19 15:32:01 Query OK, 1 row affected (0.00 sec) mysql> DELETE FROM `peng`.`binlog_test` WHERE `id`=3 AND `name`='插入数据3' LIMIT 1; #start 5601 end 5785 time 2021-11-19 15:32:01 Query OK, 1 row affected (0.00 sec)
查看是否与源数据库数据一致
源数据库
mysql> select * from binlog_test; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | +----+---------------+ 1 row in set (0.00 sec)
目标数据库
mysql> select * from binlog_test; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | +----+---------------+ 1 row in set (0.00 sec)
针对于自动同步,其目的就是让目标数据库实时拉取源数据库的
binlog
,再同步到目标数据库本身
确保源数据库的
binlog
更新间隔,取决于设置的max_binlog_size
大小及数据插入频繁率
binlog
最大存储设置:默认为1G
,建议修改为500M
,便于快速拉取处理
max_binlog_size
大小# 查看当前binlog存储最大值 mysql> show variables like 'max_binlog_size'; +-----------------+-----------+ | Variable_name | Value | +-----------------+-----------+ | max_binlog_size | 524288000 | +-----------------+-----------+ 1 row in set (0.00 sec) # 永久修改(可带单位或直接写bytes) vim /etc/my.cnf max_binlog_size=500m #max_binlog_size=524288000 # 临时修改(不能带单位,只能转换为字节bytes) set global max_binlog_size=524288000;
目的是为了导出时是否需要更换
--start-file='mysql-bin.000006'
,即binlog
文件名,若数据量极为频繁,则需要更换经测试,
500M
的binlog
存储,一般是不会被很快填满的,只要一天24
小时内此文件不被填满产生新的binlog
,我们就可以省很多事下面为测试计算过程,配置为:
max_binlog_size=500m
,因为binlog
是以event
事件为单位来存储,最后某个事件若较大,超出500m
则属于正常,一般不会太多
# 获取列表 mysql> show binary logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000010 | 525055100 | | mysql-bin.000011 | 528614358 | | mysql-bin.000012 | 550397479 | | mysql-bin.000013 | 524430486 | | mysql-bin.000014 | 527412076 | | mysql-bin.000015 | 554424041 | | mysql-bin.000016 | 524289004 | | mysql-bin.000017 | 524288328 | | mysql-bin.000018 | 529522538 | | mysql-bin.000019 | 543769836 | | mysql-bin.000020 | 524327234 | | mysql-bin.000021 | 524288472 | | mysql-bin.000022 | 604406562 | | mysql-bin.000023 | 524313044 | | mysql-bin.000024 | 524288456 | | mysql-bin.000025 | 550211581 | | mysql-bin.000026 | 524288363 | | mysql-bin.000027 | 524608627 | | mysql-bin.000028 | 541076047 | | mysql-bin.000029 | 524663266 | | mysql-bin.000030 | 524288106 | | mysql-bin.000031 | 61796217 # 编写获取binlog大小脚本 cat >> select_binlog.sh <<EOF mysql -h 172.23.0.234 -u root -peHu2016 -e 'show binary logs;' | awk 'NR > 20 {print}' >> $file echo "" >> $file EOF # 定时半小时执行一次 */30 * * * * /bin/sh /root/scripts/select_binlog.sh &>/dev/null # 查看日志 2021-11-22 15:30:01 mysql-bin.000029 524663266 mysql-bin.000030 524288106 mysql-bin.000031 49655438 2021-11-22 16:00:01 mysql-bin.000029 524663266 mysql-bin.000030 524288106 mysql-bin.000031 55292913 2021-11-22 16:30:01 mysql-bin.000029 524663266 mysql-bin.000030 524288106 mysql-bin.000031 66880555 2021-11-22 17:00:01 mysql-bin.000029 524663266 mysql-bin.000030 524288106 mysql-bin.000031 76985855 # 计算 30分钟依次相差多少 55292913 - 49655438 = 5637475 ≈ 5m 66880555 - 55292913 = 11587642 ≈ 11m 76985855 - 66880555 = 10105300 ≈ 9m # 同归都按10M来算,计算24h内能产生的binlog大小 10 * 24 = 240m
结果为
240m
,刚到我们定义的500m
的一半,故每天都可以直接获取最后一个binlog
(即最新的binlog
) 建议测试一天再进行计算,会更准确
后续随公司业务增长,需隔一段时间计算一下,若是超过500m
,则会产生新的binlog
:
脚本开头需定义
if
判断,判断binlog
是否在脚本预期范围内,若数据突增产生新的binlog
,则告警且不执行脚本,防止数据不一致
get
脚本内需增加binlog
拉取命令:一个binlog
一条拉取命令(多个则用for循环)
不建议更改
max_binlog_size
的大小,数据拉取同步会随文件大小逐渐变慢
logfile
(拉取整个binlog
);logfile、start_time、stop_time
:数据少,速度快start_time
则默认从binlog
开头拉取,截止到stop_time
stop_time
则默拉取到当前时间,从start_time
开始binlog
sql
语句也无碍,因为判断条件是表结构的所有字段都符合才会更改数据,重复执行的条件下不可能都符合import
脚本无需更改,get
时已处理完毕,直接导入即可~
同步过程中,脚本每隔1分钟执行一次,拉取当前时间~前1分钟之间的数据保持每分钟同步数据
PS:
Linux
定时任务最小单位为分钟
sql
对于重复执行的
sql
语句的测试结果如下:条件是某条数据的所有字段条件,不会误删误改其他数据
insert
:无影响,会报错重复更新此条数据,不耽误后续sql
继续执行;update
:无影响,重复更新此条数据;delete
:无影响,重复删除不报错,但也不会误删别的数据;binlog
时间间隔同步脚本:每分钟执行,确保数据实时同步
脚本条件同步间隔:确保不遗漏更新数据,且更新数据量较小
start_time:2021-11-22 12:04:33
(举例:前1分钟)stop_time:2021-11-22 12:05:33
(举例:当前时间)date +%F' %H:%M:%S':2021-11-22 13:45:00
date -d '5 mins ago' "+%F %H:%M:%S":2021-11-22 13:40:00
1 days ago
1 hours ago
1 mins ago
1 second
条件:当
binlog
过滤后不唯一(产生了多个新binlog
)时,则调用告警脚本,发送告警信息并终止脚本运行
1、钉钉-加号-发起群聊-自选-输入群名字-创建
2、进入创建的群-设置-只能群助手-添加机器人-加号-自定义机器人-添加-取名字-自定义关键字-告警内含有的关键字即可)-完成
3、复制
Webhook
monitoring.sh
需更改3处配置:
Dingding_Url
:填写创建钉钉机器人时复制的Webhook
,
Subject
:钉钉告警标题,自定义
Body
:钉钉告警内容,自定义
#!/bin/bash function SendMessageToDingding(){ Dingding_Url="https://oapi.dingtalk.com/robot/send?access_token=138a41123s4dc6d39db75cdda5f0876q88f20c748dae6c" # 发送钉钉消息 curl "${Dingding_Url}" -H 'Content-Type: application/json' -d " { \"actionCard\": { \"title\": \"$1\", \"text\": \"$2\", \"hideAvatar\": \"0\", \"btnOrientation\": \"0\", \"btns\": [ { \"title\": \"$1\", \"actionURL\": \"\" } ] }, \"msgtype\": \"actionCard\" }" } # 调用脚本时,可手动输入标题、内容(此处用$1,$2为测试用) Subject="$1" # 钉钉告警标题 Body="$2" # 钉钉告警内容 ### PS: # 生产环境调用时,$1与$2需手动定义好告警的内容; # 将此整个脚本放入if判断内,若不满足某个条件,则执行此整个告警代码块 ### SendMessageToDingding $Subject $Body
标题或内容至少一项必须带着自定义的关键词
binlog
(创建钉钉机器人时指定的关键词),否则发送失败!PS:标题与内容自身不能有空格,可用标点符号来间隔,如:
[root@web2 ~]# sh monitoring.sh '告警标题binlog' '我是告警内容!' {"errcode":0,"errmsg":"ok"}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ETTzE40R-1637745371055)(C:\Users\Peng\AppData\Roaming\Typora\typora-user-images\image-20211122190421421.png)]
脚本结构目录:
[root@web2 binlog]# tree /binlog /binlog ├── 2021-11-23_19-09-08.sql └── scripts ├── monitoring.sh ├── sync.log └── sync.sh
自动同步脚本:
sync.sh
#!/bin/bash ################################## 变量 ################################## # 数据库变量 HOST='172.23.0.234' HOST236='172.23.0.236' USER='root' PORT='3306' PWD='eHu2016' DATABASE='peng' TABLE='binlog_test' # binlog2sql变量 START_FILE=`mysql -h $HOST -u $USER -p$PWD -e 'show binary logs;' | awk 'END {print}'| awk '{print $1}'` START_TIME=`date -d '1 mins ago' "+%F %H:%M:%S"` STOP_TIME=`date +%F' %H:%M:%S'` SQL_NAME=/binlog/`date +%F'_%H-%M-%S'`.sql # 钉钉告警 SYNC_LOG=/binlog/scripts/sync.log DINGDING='/binlog/scripts/monitoring.sh' ################################## 导出 ################################## function GET(){ /usr/bin/python /opt/binlog2sql/binlog2sql-master/binlog2sql/binlog2sql.py -h $HOST -P $PORT -u $USER -p$PWD -d $DATABASE "--start-datetime=$START_TIME" "--stop-datetime=$STOP_TIME" --start-file $START_FILE > $SQL_NAME if [ $? -eq 0 ];then # 当`binlog`过滤后不唯一(产生了多个新`binlog`)时,则调用告警脚本,发送告警信息并终止脚本运行 if [ `du -sh $SQL_NAME | awk '{print $1}'` == 0 ];then rm -f `find /binlog -type f -a -size 0c` && exit fi # 分类计数导出语句 TIME=`date +%F'|%H:%M:%S'` INSERT_COUNT=`cat $SQL_NAME | grep INSERT | wc -l` UPDATE_COUNT=`cat $SQL_NAME | grep UPDATE | wc -l` DELETE_COUNT=`cat $SQL_NAME | grep DELETE | wc -l` DATA_COUNT=`cat $SQL_NAME | wc -l` ## 任务执行状态-->发送钉钉告警并写入日志 cat >> $SYNC_LOG <<EOF $STOP_TIME 从$START_FILE导出数据成功!其中: INSERT:$INSERT_COUNT条 UPDATE:$UPDATE_COUNT条 DELETE:$DELETE_COUNT条 合计:$DATA_COUNT条 EOF else echo "$STOP_TIME 从$START_FILE导出数据失败!" >> $SYNC_LOG /usr/bin/sh $DINGDING "Binlog拉取失败告警" "$TIME|FROM:$START_FILE【$SQL_NAME】" fi } ################################## 导入 ################################## function IMPORT(){ /usr/bin/mysql -h $HOST236 -u $USER -p$PWD < $SQL_NAME ## 任务执行状态-->发送钉钉告警并写入日志 if [ $? -eq 0 ];then cat >> $SYNC_LOG <<EOF $STOP_TIME 从$START_FILE导入数据成功!其中: INSERT:$INSERT_COUNT条 UPDATE:$UPDATE_COUNT条 DELETE:$DELETE_COUNT条 合计:$DATA_COUNT ####################################################### EOF else echo "$STOP_TIME 从$START_FILE导入数据成功!" >> $SYNC_LOG echo "文件来源:$SQL_NAME 有重复条目,可忽略~" >> $SYNC_LOG echo "#######################################################" >> $SYNC_LOG /usr/bin/sh $DINGDING "Binlog导入重复告警" "$TIME|FROM:$START_FILE【$SQL_NAME】有重复条目,可忽略~" fi } # 函数体调用 GET IMPORT
同步步骤:所有同步步骤都要记录时间,精确到秒!
全量同步
差异同步
- 防止数据有差异(此步骤会有重复数据条目,已测试,不影响数据一致性问题)
自动同步
- 加入定时任务,每分钟执行
检查数据一致性
实时监控sync日志,并查看目标数据库的数据与正服是否对应
- 数据是否对应:查看
get
的sql
文件,过滤某一条语句,根据条件去目标数据库进行查询,数据存在则同步成功!开始演示>>>
目标数据库导入源数据库的全备
PS:全备是从每天的
00:00:00
开始备份,比如此次备份文件的时间为:2021-11-22 00:00:00
mysql -uroot -peHu2016 < /backup/full.sql
时间戳概念:
1、源数据库定时任务时间为:
2021-11-22 00:00:00
,导入全备时间为2021-11-22 10:35:00
,则中间相差了10h; 2、需计算全备与当前的时间差,并大于此时间差才可以,防止数据遗漏,所以
start-datetime
首次同步指定为12h(记录当前时间); 3、基于上次记录时间,再次修改
start-datetime
为刚才执行同步的时间再往前退1
分钟(记录当前时间); 4、观察记录时间导入间隔,到现在同步命令应该可在10分钟内执行完导出导入,接下来进行自动同步步骤~
重复数据:
对于重复数据条目,我已做测试,可放心导入,不影响数据一致性问题(
INSERT、UPDATE、DELETE
)
全备时间:
2021-11-22 00:00:00
导出时间:
2021-11-21 22:00:00
当前时间:
2021-11-22 10:33:23
PS:导出时间是基于的全备时间,往前推2h,避免数据遗漏
/usr/bin/python /opt/binlog2sql/binlog2sql-master/binlog2sql/binlog2sql.py -h 172.23.0.234 -P 3306 -u root -peHu2016 -d peng "--start-datetime=2021-11-21 22:00:00" "--stop-datetime=2021-11-22 10:33:23" --start-file mysql-bin.000006 > `date +%F'_%H-%M-%S'`.sql
/usr/bin/mysql -h 172.23.0.236 -u root -peHu2016 < 2021-11-22_10-33-38.sql # 测试时有此类报错正常,插入或删除语句执行失败,是因为判断条件是所有字段,某条数据不对应导致就不会执行成功,不影响后续sql执行 Warning: Using a password on the command line interface can be insecure. ERROR 1062 (23000) at line 1: Duplicate entry '2' for key 'PRIMARY'
经过差异同步后,已确保可在10分钟内执行完导出导入命令:
实时监控同步日志
tailf /binlog/scripts/sync.log
,并进行以下操作:
修改时间戳为10 mins
START_TIME
变量指定为:date -d '10 mins ago' "+%F %H:%M:%S"
echo '*/1 * * * * /usr/bin/sh /binlog/sync.sh &>/dev/null' >> /var/spool/cron/root
监控拉取前10分钟的数据
[root@web2 ~]# tailf /binlog/scripts/sync.log ####################################################### 2021-11-24 13:18:01 从mysql-bin.000006导出数据成功!其中: INSERT:31条 UPDATE:11条 DELETE:30条 合计:72条 2021-11-24 13:18:01 从mysql-bin.000006导入数据成功! 文件来源:/binlog/2021-11-24_13-18-01.sql 有重复条目,可忽略~
2 mins
监控日志导入成功后修改时间戳:
START_TIME
变量指定为:date -d '2 mins ago' "+%F %H:%M:%S"
PS:若在
1
分钟内日志显示导入完成,这可直接修改为1 mins
修改时间戳为2 mins
sed -i 's/10 mins/2 mins/g' sync.sh
监控拉取前2
分钟的数据
####################################################### 2021-11-24 13:20:01 从mysql-bin.000006导出数据成功!其中: INSERT:3条 UPDATE:2条 DELETE:2条 合计:7条 2021-11-24 13:20:01 从mysql-bin.000006导入数据成功! 文件来源:/binlog/2021-11-24_13-20-01.sql 有重复条目,可忽略~
1 mins
监控日志导入成功后修改时间戳:
START_TIME
变量指定为:date -d '1 mins ago' "+%F %H:%M:%S"
此时还会有【重复条目】的日志提示,但第二次运行时将不再有重复日志
修改时间戳为1 mins
sed -i 's/2 mins/1 mins/g' sync.sh
监控拉取前1
分钟的数据
####################################################### 2021-11-24 13:21:01 从mysql-bin.000006导出数据成功!其中: INSERT:2条 UPDATE:1条 DELETE:1条 合计:4条 2021-11-24 13:21:01 从mysql-bin.000006导入数据成功!其中: INSERT:2条 UPDATE:1条 DELETE:1条 合计:4 文件来源:/binlog/2021-11-24_13-21-01.sql 有重复条目,可忽略~
再次监控拉取前1
分钟的数据
此时已显示的还是刚才的日志,说明已经没有重复
sql
,也没有新的数据,若有新sql
则会输出新的数据日志;至此完成自动同步的所有步骤,且
sync.log
导入成功不应该有输出,除非有重复执行的sql
####################################################### 2021-11-24 13:21:01 从mysql-bin.000006导出数据成功!其中: INSERT:2条 UPDATE:1条 DELETE:1条 合计:4条 2021-11-24 13:21:01 从mysql-bin.000006导入数据成功!其中: INSERT:2条 UPDATE:1条 DELETE:1条 合计:4 文件来源:/binlog/2021-11-24_13-21-01.sql 有重复条目,可忽略~
场景了解参见:场景介绍
思路:真实场景下,生成的回滚
sql
经常会需要进一步筛选,查看里面是否有别的表的dml
语句以及本表的非delete操作的语句,结合grep
、编辑器等
PS1
:使用-B
选项生成回滚sql
,检查回滚sql
是否正确(注意:insert
也会被解析成delete语句!!!) 使用
-B
转换时,先不用-B选项导出sql
,除delete
语句外,其余语句一并删除,否则insert
被解析为delete
,执行完你就叽叽了…
PS2
:为何只回滚转换delete语句?
insert、update
是插入、更新的语句,没有被删除操作,所以无需回滚,且就算回滚也会相应的多插了一条;
delete
是将记录删除了,所以只需要恢复被删除的记录即可
INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3');
mysql> select * from binlog_test; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | | 2 | 插入数据2 | | 3 | 插入数据3 | +----+---------------+ 3 rows in set (0.00 sec)
记录删除时间:
2021-11-24 16:38:43
删除数据
DELETE FROM `peng`.`binlog_test` WHERE `id`=1; DELETE FROM `peng`.`binlog_test` WHERE `id`=2; DELETE FROM `peng`.`binlog_test` WHERE `id`=3;
查看数据,已被删除
mysql> select * from binlog_test; Empty set (0.00 sec)
加
-B
选项,进行反解析sql
,此选项主用于恢复被删除的数据PS:
insert
解析为delete
delete
解析为insert
update
不会改变
--start-datetime
:删除数据的时间,若忘记可提前1分钟甚至更多,重复的sql
不会执行且不影响后续sql
执行
--stop-datetime
:当前时间
拉取命令
删除时间为
2021-11-24 16:38:43
,拉取时间也指定为此时间戳,若拉过来不对,则指定的时间提前几秒
binlog2sql -h 172.23.0.234 -P 3306 -u root -peHu2016 -d peng -t binlog_test --start-file='mysql-bin.000006' --start-datetime='2021-11-24 16:38:43' --stop-datetime='2021-11-24 16:45:45' -B > recover.sql [root@web2 ~]# !vim
拉取结果
已经获取到数据被删除的
sql
语句此时结果已被反解析,三条
insert
被解析为delete
,两条delete
则被解析为insert
[root@web2 ~]# cat recover.sql INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 29232 end 29416 time 2021-11-24 16:38:43 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 29017 end 29201 time 2021-11-24 16:38:43 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 28802 end 28986 time 2021-11-24 16:38:43
注意!当数据量过多时,难免会含有
insert
语句,insert
语句也会同时被反解析为delete
语句,我们只需要恢复数据,故将反解析出的delete
语句剔除掉即可,只保留被反解析的insert
语句
INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 29232 end 29416 time 2021-11-24 16:38:43 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 29017 end 29201 time 2021-11-24 16:38:43 INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 28802 end 28986 time 2021-11-24 16:38:43
mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (3, '插入数据3'); #start 29232 end 29416 time 2021-11-24 16:38:43 Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (2, '插入数据2'); #start 29017 end 29201 time 2021-11-24 16:38:43 NTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 28802 end 28986 time 2021-11-24 16:38:43Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO `peng`.`binlog_test`(`id`, `name`) VALUES (1, '插入数据1'); #start 28802 end 28986 time 2021-11-24 16:38:43 Query OK, 1 row affected (0.00 sec)
查询被删除的数据是否已恢复:已恢复
mysql> select * from binlog_test; +----+---------------+ | id | name | +----+---------------+ | 1 | 插入数据1 | | 2 | 插入数据2 | | 3 | 插入数据3 | +----+---------------+ 3 rows in set (0.00 sec)