场景是这样子的:
如果有人不小心删了数据库,怎么办?
主从?恐怕不行,数据实时同步,备库的数据也被删了。
那从库延迟同步,如何?嗯嗯,应该可以。那问题来了。如果延迟同步的情况下,发生数据库误删除,运维人员赶紧切到从库上,终究是能尽快的恢复业务,只是有一部分数据会丢失,那么怎样让服务继续运行的情况下,补回那一部分丢失的数据呢?
这种情况下,我的脚本就派上用场了!
我的思路是这样子的:
忘记一件事,强调一下,在切换到从库之前,请将关键表中的主键如果是自增ID,那请将自增ID向后增大一定数值,这样是为了让丢失的数据能补回!
alter table users AUTO_INCREMENT=xxxxx; 这个语句应该是可帮助你的.
有些请款,可能需要暂时关闭外键set foreign_key_checks=0;
言归正传的讲,我们当时的场景是这样的,我们用的阿里云的RDS,所以恢复之前还得先下载binlog日志。
所以准备条件就这样的:
1. 需要在阿里云上创建一个子账号,
2. 需要aliyuncli工具调用RDS接口,得到binlog日志内网下载地址。
3. 需要在灾备RDS上创建一个binlog的账号
4. 需要一个下载binlog日志并能解包的脚本
5. 需要一个将binlog日志转换成可用sql的脚本
开始干活写脚本:
1. 利用aliyuncli工具,输入如下命令:
aliyuncli rds DescribeBinlogFiles--DBInstanceId rdsid --StartTime 2017-02-15T14:00:00Z --EndTime2017-02-15T14:30:00Z
脚本:
#!/usr/bin/python
#coding:utf-8
import os,sys
import json
import time
def get_url():
#urlContent = os.popen("aliyuncli rds DescribeBinlogFiles--DBInstanceId rdsid --StartTime 2017-02-17T10:00:00Z --EndTime2017-02-17T12:00:00Z")
DBId = ''
starttime = '2017-02-20 09:00:00'
endtime = '2017-02-20 12:00:00'
starttime = conv_time(starttime,8)
endtime = conv_time(endtime,8)
urlContent = os.popen("aliyuncli rds DescribeBinlogFiles--DBInstanceId %s --StartTime %s --EndTime%s"%(DBId,starttime,endtime)).read()
urlContent = json.loads(urlContent)
urlfile = file('urlfile','w+')
for url in urlContent['Items']['BinLogFile']:
if url['HostInstanceID'] == 1669377:
print url
urlfile.write('%s\n'%url["IntranetDownloadLink"])
urlfile.close()
def conv_time(n_time,n=8):
s_time = time.mktime(time.strptime(n_time,"%Y-%m-%d%H:%M:%S"))
addtime = 3600 * n
f_time = s_time -addtime
n_time =time.strftime("%Y-%m-%dT%H:%M:%SZ",time.localtime(f_time))
return n_time
if __name__ == '__main__':
get_url()
2. 得到的内网地址,放入urlfie文件
#!/bin/bash
wget -c -i /opt/binlog/rds_binlog/urlfile-P /opt/binlog/rds_tar
if [ $? != 0 ];then
echo "wget error"
fi
cd /opt/binlog/rds_sql
ls /opt/binlog/rds_tar/*.tar* |xargs -n1tar xvf
3. 利用python脚本对binlog日志进行转换
脚本思路:
1. 利用binlog工具进行转换成sql,但是sql有些需要去转换成我们可识别的形式
2. 转换sql,查询mysql的表字段,利用正则表达式匹配insert,delete,update的语句,将所有@1这种类型的字段进行转换
#encoding:UTF-8
#!/usr/bin/python
import os,sys,re,getopt
import MySQLdb
import time,datetime
host =''
user = ''
password = ''
port = 3306
start_datetime = ''
stop_datetime = ''
start_position = ''
stop_position = ''
database = ''
mysqlbinlog_bin = 'mysqlbinlog -v'
binlog = ''
fileContent = ''
output='rollback.sql'
only_primary = 1
tmp_binlog_file ="tmp_binlog_file"
field_list = ''
#----------------------------------------------------------------------------------------
# 功能:获取参数,生成相应的binlog解析文件
#----------------------------------------------------------------------------------------
def getopts_parse_binlog():
globalhost
globaluser
globalpassword
globalport
globalfileContent
globaloutput
globalbinlog
globalstart_datetime
globalstop_datetime
globalstart_position
globalstop_position
globaldatabase
globalonly_primary
try:
options,args= getopt.getopt(sys.argv[1:],"f:o:h:u:p:P:d:",["help","binlog=","output=","host=","user=",\
"password=","port=","start-datetime=","stop-datetime=","start-position=","stop-position=","database=","only-primary="])
exceptgetopt.GetoptError:
print"参数输入有误!!!"
options= []
ifoptions == [] or options[0][0] in ("--help"): #如果输入错误或者--help则提示帮助信息
usage() #显示帮助信息
sys.exit()
print"正在获取参数......"
printoptions
forname, value in options:
ifname == "-f" or name == "--binlog":
binlog= value
elifname == "-o" or name == "--output":
output= value
elifname == "-h" or name == "--host":
host= value
elifname == "-u" or name == "--user":
user= value
elifname == "-p" or name == "--password":