记录一次数据同步导致的“删库”事故

时间

2020年8月11下午4点多

前因后果

我司项目环境分为:开发环境(服务和数据库),线上环境(服务和数据库).....。 今天有个新需求,涉及到数据库表的变动,我在测试环境把表设计好,然后需要把改动的表结构同步到线上环境数据库。由于我没有线上数据库的读权限。就叫同事帮忙同步。同事每次干这种同步表结构的事情都是采用navicat自带的同步功能(如上图)。正常操作就是点击上图的“结构同步”进行开发和线上环境数据库的表结构进行差异比对。对不同的地方勾选进行选中同步。这个时候负责同步的同事失误操作点成了数据同步。 导致的结果就是把测试环境的测试数据同步到线上了。

由于被测试环境数据覆盖的线上数据库涉及到用户信息(支付服务)。直接影响到线上环境依赖于这个数据库所在的服务(支付服务)不能正常运行。

当即想到的就是对被覆盖的线上数据库进行“回滚操作”,回滚到覆盖前某一时刻,由于使用的是阿里云RDS数据库自带容灾功能。就很顺利的恢复到覆盖前的某一时刻了(事故发生时间是下午四点多,我们通过阿里云rds自带的容灾恢复到了下午四点,难免的有个时间差)。

恢复以后发现线上在继续报错,原来是这个数据库的很多表采用的是“自增主键”,其他依赖这个服务的数据库就是根据这个库的自增主键关联的,由于覆盖库恢复以后自增主键的自增基数回退到了恢复的那一刻重新开始自增。就导致悲剧了,回退以后开始“重新自增”导致其他服务拿到了重复的关联主键。 就好比A找B要号,当B从1自增到6以后把B的自增点突然改成3,这个时候A再次找B拿号拿到的就是4,5,6。 由于4,5,6在A中已经出现过了,就导致重复,这就影响了业务。

解决方案就是找到A中后面重复的B服务中的id(4,5,6),把这些id在A,B服务中都统一加一个数(加的200)保证不重复并且两边关联正确就解决了。

还有一个问题就是在覆盖的时候到数据库回退的期间在B服务中产生的数据就找不回来了,这个时候需要通过分析A服务中调用过B服务产生的数据来手动推出和修补B中的数据(有难度,由于推出这些数据工作量很大,我们就没推了,我们这里的B服务就是公司的支付服务,影响的就是当天的对账功能,直接手动确认当天对账功能,这点的解决方案比较简单粗暴,还好不影响正常交易和客户的数据显示)。

总结

  1. 线上数据库一定要做容灾处理,我们这次还好使用的是阿里云RDS自带容灾功能,可以恢复到以前的任何时间点,只不过阿里云的这个功能恢复比较缓慢,猜想阿里云rds的实现方式是增量记录数据库的所有操作日志,通过这个增量日志来实现的回退到数据库之前的具体一个时间点。要是这里是自己在服务器上面安装的mysql没有做容灾备份就后果不堪设想。 
  2. 有外面服务依赖的外键订单号不要采用自增id给别的服务依赖保存,不然遇到这种数据库回退的情况就会导致回退以后重新获取的id跟回退之前的id重复冲突。最好的办法就是这种要暴漏给其他服务依赖的“外键”通过雪花算法或者随机字符串的方式(简单的例子:比如做微信和支付宝支付的时候保存腾讯和支付宝的支付单id就不是采用的自增,而是采用的字符串的方式)
  3. 要敬畏每次线上操作啊,数据库表结构同步,数据库数据同步,服务上线等等线上操作。以前在货车帮的时候这种涉及到数据库表结构变动的都是开发人员会通过公司的一个系统提变动的sql申请单子(里面包含要执行的sql),然后由DBA审核后DBA执行,这样就规避了单个人直接操作的风险。要是这次是我造成的事故,估计可能就跑路了(开个玩笑)。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值