文章目录
- `MySQL-binlog2sql`:非主从实时同步+恢复误删数据
MySQL-binlog2sql
:非主从实时同步+恢复误删数据
1.引
1)介绍
针对于DBA
或开发人员,有时会误删或者误更新数据,如果是线上环境并且影响较大,就需要能快速回滚。
传统恢复方法是利用备份重搭实例,再应用去除错误sql
后的binlog
来恢复数据。此法费时费力,甚至需要停机维护,并不适合快速回滚。也有团队利用LVM
快照来缩短恢复时间,但快照的缺点是会影响mysql的性能。现在有不少好用而且效率又高的开源闪回工具如【binlog2sql、mysqlbinlog_flashback
】,这些工具在工作中给DBA
减轻了不少痛苦,以下针对binlog2sql
的使用进行实践演练。
2)功能
- 数据快速回滚(闪回)
- 主从切换后数据不一致的修复
- 从
binlog
生成标准SQL
,带来的衍生功能(sql
可直接执行的那种~)
3)针对两种场景
-
场景1:用来拉取
binlog
,同步到其它数据库- 无论是增删改查,都要同步到另一个数据库,所有数据均保持一致
- 所需数据库
- 源数据库,此处为【
mysql234
】 - 目标数据库,此处为【
mysql236
】
- 源数据库,此处为【
- 自动化同步
binlog
所有数据到目标数据库
- 所需数据库
- 无论是增删改查,都要同步到另一个数据库,所有数据均保持一致
-
场景2:用
binlog2sql
主要做紧急恢复来使用- 针对于误操作删除了数据,用来做数据紧急恢复
- 所需数据库
- 主数据库,此处为【
mysql234
】
- 主数据库,此处为【
- 手动同步
binlog
误删数据
- 所需数据库
- 针对于误操作删除了数据,用来做数据紧急恢复
- 两者区别:
-B
选项- 最大的区别取决于增加此选项,此选项是将处理后的
纯sql语句
反向解析,即:-
insert
解析为delete
-
delete
解析为insert
-
update
不会改变
-
- 最大的区别取决于增加此选项,此选项是将处理后的
2.先决条件
原理:主要是对于
delete
操作,从binlog
取出delete
信息,生成insert
的回滚语句。对于insert
操作,回滚SQL
是delete
。对于update
操作,回滚sql
应该交换SET
和WHERE
的值。
1)安装MySQL
参见:MySQL安装部署启动
2)修改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(默认)
3.安装binlog2sql
推荐,百度云打包的文件是经我测试过的,不用担心版本问题,下载上传后可直接执行后面的解压安装命令
- 安装所需依赖工具包列表
python-pip
PyMySQL
python-mysql-replication
wheel argparse
1)解压
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
2)安装
若报错,则安装
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
3)添加别名
方便一键调用,不用再单独执行
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
4.准备测试数据
1)建库建表
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;
2)插入数据
记录插入数据的时间,精确到秒,此时是【
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');
3)查看数据
mysql> SELECT * FROM `peng`.`binlog_test`;
+----+---------------+
| id | name |
+----+---------------+
| 1 | 插入数据1 |
| 2 | 插入数据2 |
| 3 | 插入数据3 |
+----+---------------+
3 rows in set (0.00 sec)
4)模拟误删除数据
模拟开发人员误删除数据,此时时间是【
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)
5.场景1(数据实时同步)
场景了解参见:场景介绍
导出后会自动优化为纯
sql
语句,无没用的部分,可直接在数据库执行的那种~
1)案例
1、数据导出
导出前询问误删除数据的时间,精确到秒,基于上面的例子,记不清楚的话往后延迟几秒:【
2021-11-19 15:33:00
】导出后可见,插入的三条和删除的两条都有记录,且后面带有
position
(位置点)、操作的时间记录
1> 导出命令
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
2> 导出结果
[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
2、数据导入
检查需要对应的
posistion
位置点、数据信息、时间点,确认无误后,方可导入至另一台数据库另一台数据库要有对应结构、同名的库、表,或另一台已经导入过此数据库的全量数据(前提是上面插入的数据是在导入全量之后插入的)
PS:若数据量大,则可直接库外导入
sql
,或利用数据库工具来导入在另一台导入上面的
sql
,发现与源数据库的数据是相同的,成功~
1> 导入命令
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
2> 导入结果
[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)
3> 查看数据一致性
查看是否与源数据库数据一致
-
源数据库
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)
2)自动同步
针对于自动同步,其目的就是让目标数据库实时拉取源数据库的
binlog
,再同步到目标数据库本身
1、配置源数据库
确保源数据库的
binlog
更新间隔,取决于设置的max_binlog_size
大小及数据插入频繁率
binlog
最大存储设置:默认为1G
,建议修改为500M
,便于快速拉取处理
1> 配置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;
2> binlog更新频率计算
目的是为了导出时是否需要更换
--start-file='mysql-bin.000006'
,即binlog
文件名,若数据量极为频繁,则需要更换经测试,
500M
的binlog
存储,一般是不会被很快填满的,只要一天24
小时内此文件不被填满产生新的binlog
,我们就可以省很多事下面为测试计算过程,配置为:
max_binlog_size=500m
,因为binlog
是以event
事件为单位来存储,最后某个事件若较大,超出500m
则属于正常,一般不会太多
1>> 计算过程
# 获取列表
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
2> 结论
结果为
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
开始 - PS:都不指定,则拉取整个
binlog
- PS:就算有重复的
sql
语句也无碍,因为判断条件是表结构的所有字段都符合才会更改数据,重复执行的条件下不可能都符合
- 第一条 ~ 最后一条不指定时间,只指定
-
import
脚本无需更改,get
时已处理完毕,直接导入即可~
-
2、注意事项
同步过程中,脚本每隔1分钟执行一次,拉取当前时间~前1分钟之间的数据保持每分钟同步数据
PS:
Linux
定时任务最小单位为分钟
1> 重复执行的sql
对于重复执行的
sql
语句的测试结果如下:条件是某条数据的所有字段条件,不会误删误改其他数据
-
insert
:无影响,会报错重复更新此条数据,不耽误后续sql
继续执行; -
update
:无影响,重复更新此条数据; -
delete
:无影响,重复删除不报错,但也不会误删别的数据;
2> 同步binlog
时间间隔
-
同步脚本:每分钟执行,确保数据实时同步
-
脚本条件同步间隔:确保不遗漏更新数据,且更新数据量较小
-
start_time:2021-11-22 12:04:33
(举例:前1分钟) -
stop_time:2021-11-22 12:05:33
(举例:当前时间)
-
3> 时间获取格式示例
- 当前时间:
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小时:
1 days ago
- 前1分钟:
1 hours ago
- 前1分钟:
1 mins ago
- 前1秒钟:
1 second
- 前1小时:
3、钉钉告警
条件:当
binlog
过滤后不唯一(产生了多个新binlog
)时,则调用告警脚本,发送告警信息并终止脚本运行
1> 创建钉钉机器人
1、钉钉-加号-发起群聊-自选-输入群名字-创建
2、进入创建的群-设置-只能群助手-添加机器人-加号-自定义机器人-添加-取名字-自定义关键字-告警内含有的关键字即可)-完成
3、复制
Webhook
2>钉钉告警脚本
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
3> 测试脚本
标题或内容至少一项必须带着自定义的关键词
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)]
4、同步脚本
脚本结构目录:
[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
5、开始测试
同步步骤:所有同步步骤都要记录时间,精确到秒!
全量同步
差异同步
- 防止数据有差异(此步骤会有重复数据条目,已测试,不影响数据一致性问题)
自动同步
- 加入定时任务,每分钟执行
检查数据一致性
实时监控sync日志,并查看目标数据库的数据与正服是否对应
- 数据是否对应:查看
get
的sql
文件,过滤某一条语句,根据条件去目标数据库进行查询,数据存在则同步成功!开始演示>>>
1> 全量同步
目标数据库导入源数据库的全备
PS:全备是从每天的
00:00:00
开始备份,比如此次备份文件的时间为:2021-11-22 00:00:00
mysql -uroot -peHu2016 < /backup/full.sql
2> 差异同步
时间戳概念:
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
)
1>> 源数据库导出
全备时间:
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
2>> 导入到目标库
/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'
3> 自动同步
经过差异同步后,已确保可在10分钟内执行完导出导入命令:
实时监控同步日志
tailf /binlog/scripts/sync.log
,并进行以下操作:
1>> 加入定时任务
-
修改时间戳为
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>> 修改时间戳为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 有重复条目,可忽略~
3>> 修改时间戳为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 有重复条目,可忽略~
6.场景2(数据紧急恢复)
场景了解参见:场景介绍
思路:真实场景下,生成的回滚
sql
经常会需要进一步筛选,查看里面是否有别的表的dml
语句以及本表的非delete操作的语句,结合grep
、编辑器等
PS1
:使用-B
选项生成回滚sql
,检查回滚sql
是否正确(注意:insert
也会被解析成delete语句!!!) 使用
-B
转换时,先不用-B选项导出sql
,除delete
语句外,其余语句一并删除,否则insert
被解析为delete
,执行完你就叽叽了…
PS2
:为何只回滚转换delete语句?
insert、update
是插入、更新的语句,没有被删除操作,所以无需回滚,且就算回滚也会相应的多插了一条;
delete
是将记录删除了,所以只需要恢复被删除的记录即可
1)准备数据
1、插入数据
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');
2、查看数据
mysql> select * from binlog_test;
+----+---------------+
| id | name |
+----+---------------+
| 1 | 插入数据1 |
| 2 | 插入数据2 |
| 3 | 插入数据3 |
+----+---------------+
3 rows in set (0.00 sec)
3、模拟删除
记录删除时间:
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)
2)数据恢复
加
-B
选项,进行反解析sql
,此选项主用于恢复被删除的数据PS:
insert
解析为delete
delete
解析为insert
update
不会改变
1、数据拉取
--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
2、数据导入
注意!当数据量过多时,难免会含有
insert
语句,insert
语句也会同时被反解析为delete
语句,我们只需要恢复数据,故将反解析出的delete
语句剔除掉即可,只保留被反解析的insert
语句
1> 导入命令
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
2> 执行过程
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)
3> 查询数据是否恢复
查询被删除的数据是否已恢复:已恢复
mysql> select * from binlog_test;
+----+---------------+
| id | name |
+----+---------------+
| 1 | 插入数据1 |
| 2 | 插入数据2 |
| 3 | 插入数据3 |
+----+---------------+
3 rows in set (0.00 sec)