一场由 DBA 犯错,外键放大的事故分析

本来注定平淡的一天,就像骄阳下的树叶,没有一点精神。

日常修正

批了一个数据修正的单子,产品上有一个评价的功能,从设计时就坚持公平公正,但还是没顶住运营的压力,经常会删除一些不好的评论。与是就会经常的修正线上的数据。典型的理想和现实的差别。

紧急事件

十一点钟,忽然运营反馈老师的课程不见了,刚开始以为这个老师重新注册了 id,或者其它。慢慢的反馈越来越多,感觉有点头大。

然而越来越多的消息指向问题,来自外界和内部。

初步猜想

刚好,因为公司泄露 appkey 的事情闹得满城风雨,在想是不是因为哪些密码被泄露然后导致有人黑我们。

这种阴谋论细想就不大可能了,有谁能这么精确的知道我们的数据模型,所有丢失的课程都是一些好的课程。而且就算拿到 DB 密码,也需要在内网的某个环境,又懂业务,又懂技术,这几个人就在我们面前呀。

又花了不少时间,排除另一个论证。

排除一切不可能的,剩下的即使再不可能,那也是真相。

问题在 DBA?

这时,把想法又放回到数据修正时的操作。

发现 DB 中的数据有几个点也指向这里,比如说数据在上午9点多时,id 从 8k 跳到 98w。

于是开始讨论方案,最后选择从昨晚的备份中恢复。

下午3点多钟,困的想抽烟,最后用一瓶可乐解决。

第一张表恢复完,发现搜索可以,但不能用分类筛选,再恢复第2张 2W 量级的 tag 关联表。

本以为完事了,结果产品反馈,用户的订阅数据也丢失了一部分。

此时,感觉就像个无底洞,到底干了什么。

订阅记录的量级在 10M,这种可不像上两张表,几分钟进行恢复。而是达数小时的重新写回数据库。

恢复过程中,也想了下原因。

假设

DBA 拿到用于修正数据的 CSV 的数据后,用 MySQL 的 replace into 方法,对课程表进行更新,但不小心将一些课程进行了删除。

本以为只有 10K 条数据的,也没大放心上,照理做任务前先做了备份。

但这几张表是历史老表,表间是有外键关联的。

于是主表的 ID 被删除之后,导致 20K 的标签表和 10M 的用户记录表都被删除或者引用变为空。

外键

对于外键,各说纷纭,目前主流的观点是不用外键,毕竟孤岛数据已经不是问题。

但外键引发的问题远远大于几个孤岛数据。

完结

整个恢复工作一直进行到深夜,为了数据安全,是用单行恢复的方式。

这就是一个典型的操作时犯傻,外键引用放大的事件。