记一次数据库"脑裂"问题的复盘

2021/05/07 873点热度 0人点赞 0条评论

问题回顾

  • 4月2日 开发发现专有云的用户rds实例链接数报警,并于中午发起了数据库配置变更申请;

  • 4月8日14:00 某云在场运维巡检,发现该实例有中断的任务,尝试补偿执行失败;

  • 4月8日14:23 某云在场运维直接手动操作跳过一些步骤,将中断任务继续执行;

  • 4月8日17:30,许久没消息的报警群,突然收到一堆报警,用户系统提示:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException,其他系统提示调用用户系统Read timed out,后续又报Connection refused

  • 4月8日17:35 开发在堡垒机上尝试连接数据库,发现无法telnet通

  • 4月8日17:36 上升到DBA,发现该实例在已经不存在;

  • 4月8日17:40 上升到某云,在场运维排查后无法解决;

  • 4月8日17:50 开始呼叫总部支持;

  • 4月8日18:00 发现rds对应的vip后续无挂载实例;

  • 4月8日18:05 通过元数据发现对应的主实例;

  • 尝试通过应用程序挂载主实例,多次尝试失败;

  • 4月8日18:25 某云内部沟通,让运维直接手动操作,挂载成功;

  • 4月8日18:29 数据库连接恢复,应用恢复正常;

  • 4月8日18:35 验证整体流程没问题;

  • 4月9日10:00 安排开发对数据进行抽样排查;

  • 4月9日10:15 测试发现从库从4月8日14:23 后无同步记录(堡垒机无主库操作权限);

  • 4月9日10:30 开发通过调用链随机抽取数据发现当时注册成功但数据库无数据;

  • 4月9日10:45 开发通过后台接口查验,发现数据库无数据(后台);

  • 4月9日10:50 申请堡垒机主库访问权限;

  • 4月9日11:00 确认主库4月8日18:30之前无数据;

  • 4月9日11:10 让开发查询小于4月8日最后一条数据,发现数据时间为4月2日12:11;

  • 4月9日11:15 安排开发开发登录/注册拦截功能,并批量将问题用户缓存删除;

  • 4月9日11:20 让DBA操作用户关键表结构,将主键+100万的操作;

  • 4月9日12:00 DBA无法通过脚本+100w修改数据库自增主键;

  • 4月9日12:20 让DBA对关键表进行insert数据,并指定主键操作;

  • 4月9日12:30 DBA将所有的数据同步任务停止,批量完成主键修改;

  • 4月9日13:00 将区间用户4月2日至4月9日所有的新用户导出;

  • 4月9日14:00 讨论影响范围以及具体方案;

  • 4月9日14:30 某云来现场复盘该问题,并制定后续方案;

  • 4月9日15:00 上线第一版拦截;

  • 4月9日15:33 发现用户数据库链接数过多,无法链接;

  • 4月9日15:40 查看监控发现数据库监控指标除了链接数,其他无问题;

  • 4月9日15:45 DBA和现场运维尝试修改数据库链接数,修改几次失败;

  • 4月9日15:50 已无数据进行;

  • 4月9日15:52 发现项目初始化链接过多,安排开发将初始化链接降到10/20,最大降到50/100;

  • 4月9日15:55 链接数据库发现大量的慢sql,基于主键的查询也几百秒了;

  • 4月9日16:00 kill一批大于2秒的sql,发现还慢,执行explain发现explain都得执行十来秒,初步怀疑磁盘有问题;

  • 4月9日16:05 再次无法连接;

  • 4月9日16:10 让驻场运维开始kill 慢sql,同时询问有无办法进行漂移;

  • 4月9日16:20 偶然听到旁边一运维哥们说了一句备份的事,并确认复盘完了怕现有实例有问题,进行一次全量备份;

  • 4月9日16:25 停止掉全量备份,业务恢复;

  • 4月9日17:00 监测到还有漏网用户进来;

  • 4月9日18:00 开发修改代码上线,彻底堵住;

某云扩容机制

图片

用户申请扩容流程

  • 创建临时实例

  • 将主实例最近的全量备份恢复到临时实例

  • 然后追加binlog和主实例保持同步

  • 修改VIP链接地址,将主vip指向临时实例,从实例的同步也从临时实例同步(这之间会有一些缓存处理机制,保证数据不丢失,只会闪断)

  • 修改rds的元数据信息,将原主标记为临时,临时标记为主实例

  • 释放元数据为临时实例的节点

问题分析

在扩容的时候,第4部成功,第5部卡住,导致流程中断。

  • 4月8日14点左右 调试任务时,尝试将中断任务恢复,但恢复失败;

  • 4月8日14:23 直接手动操作,跳过步骤5,直接执行步骤6

  • 但是此时rds的元数据中新的实例还是临时实例的标签,但实际上已经变成了主实例,后端操作程序并没有做强校验,只是把临时实例上的同步给中断,进入待释放状态;

  • 直到17:30分,才彻底释放完成,因此vip上连接的主实例丢失,也无法通过后端进行修复;

  • 4月8日18:05,通过元数据发现的主实例,其实4月2日的主实例

  • 4月8日18:25 运维通过手动挂载的实例,其实数据是不一致的;

  • 4月9日12:00 让DBA更改自增主键时,大数据在做同步数据初始化操作,导致锁表,无法操作;

  • 4月9日15:33 运维全量备份导致表被锁

问题处理

说明:

  • 由于后续业务流程中用户主键作为一个业务唯一标识关联用户数据;

  • 当4月8日18:25分恢复数据库后,在4月2日到4月9日12点调整主键id之间的用户数据都可能会错乱;

  • 可能A用户4月2日来的时候id是3,4月8日18:30分后再来可能变成了5,B用户可能变成了3

处理:

  • 针对之间的用户进行登录、注册拦截;

  • 将这批用户的缓存全部清空;

  • 将主键id进行手动扩容;

  • 然后针对业务数据进行清洗处理;

  • 由于涉及到业务,具体处理措施不在此处明说

  • 最后放开这批用户,让用户进行操作

事后总结

  • 生产无小事,运维的任何操作必须和业务同步;

  • 经过业务允许后在可操作的时间范围内进行操作,禁止在业务高峰期操作;

  • 针对所有的操作必须要有验收,具体验收规则根据实际情况来;

  • 关联业务系统不能强依赖自增主键,业务主键必须自己生成,必须一个用户唯一,再来还是一样,比如业务主键hash后+业务主键后4位;

  • 针对生产事故,必须重视,投入最大的资源去保障业务的稳定性;

yxkong

这个人很懒,什么都没留下

文章评论