凌晨两点,手机在床头柜上疯狂震动。我眯着眼摸到手机,屏幕上弹出的告警消息让睡意瞬间清零——生产环境的订单表被误删了。那种心跳漏半拍、手心冒冷汗的感觉,做过运维的都懂。其实数据库误删这事儿,说大不大说小不小,处理得当就是虚惊一场,处理不当就是连夜写故障报告加全公司通报。今天不聊那些晦涩的官方文档,就说说我自己踩坑踩出来的三招,真遇到事儿了能救命。

先说第一招,也是最容易忽略的一招——确认你的备份策略到底靠不靠谱。很多团队嘴上说着有备份,实际上备份脚本写完了就没再管过。我之前在某家电商公司就碰到过,数据库每周日全量备份,但那个备份文件已经连续三周没更新了,因为磁盘满了,cron任务一直在报错,但没人看日志。结果周四删了数据,备份还是周日的,恢复出来丢了三天的订单。所以别光问“有没有备份”,要问“备份能不能用”。每季度做一次恢复演练,不是走过场,是真把备份文件拉到测试环境里跑一遍,确认能正常拉起服务。另外,备份别跟数据库放同一台机器,不然硬盘烧了或者机房断电,备份也跟着陪葬。异地备份或者至少对象存储,该上就上。
第二招,如果你用的是MySQL或者PostgreSQL这类支持事务的数据库,binlog或者WAL日志就是你最靠谱的朋友。误删之后第一件事别慌,先确认操作时间节点,然后立刻把binlog导出来,用mysqlbinlog工具定位到误删语句之前的位置,把后面的操作重放一遍到临时库。我见过最快的一次恢复,从接到告警到数据完全找回来,不到四十分钟,全靠binlog把误删的数据一条条捞回来了。这里有个小细节:binlog的保留时间一定要设够,别只留一天。有些业务高峰期一天能产出几十GB的binlog,磁盘压力大,很多DBA就顺手把保留时间改成12小时,结果出事儿的时候正好覆盖不到。建议至少保留三天,磁盘不够就压缩归档。
第三招比较冷门,但关键时刻能救命——利用延迟从库。所谓延迟从库,就是故意让从库落后主库一段时间,比如落后两个小时。平时可能觉得这功能没什么用,但一旦主库数据被误删,延迟从库就成了时间机器。你直接把它停掉,从它上面把数据导出来,再补到主库去。这个方法的好处是快,不用翻binlog一点点找,缺点是前提是你得提前配好。很多团队嫌麻烦不搞这个,我建议有条件的一定要配,尤其是核心业务库,多花点存储成本换一份安心,这笔账很划算。我见过最惨的案例,一个初创公司没有从库也没有效备份,误删之后只能靠开发手动补数据,补了两天两夜才勉强恢复,业务停了整整一个周末。
说完这三招,再聊点实操细节。无论用哪种方式恢复,恢复完别急着切流量,先在临时库上做数据校验。怎么校验?把关键表的行数、业务上特殊的指标(比如订单总额)跟误删前的监控数据对一下,确认无误再切换。另外,恢复期间把写操作先停掉,或者只读模式,不然主库持续有新的写入,恢复的数据可能跟新数据冲突。还有个小坑,binlog里如果有DDL语句,比如删表、改表结构,恢复的时候要特别小心,最好单独处理,别一股脑重放,不然可能把表结构改了导致后续数据对不上。
其实数据库误删这事儿,拼的不是谁的技术更牛逼,而是谁提前做了准备。我见过很多团队,平时喊着“稳如泰山”,真出了事儿才发现备份是坏的、binlog没开、从库也没有,一堆人围在一起干瞪眼。反过来,那些处理得快的团队,并不是他们运气好,而是把各种可能性都提前演练过了。就像消防演习,真着火的时候能跑出来的,都是练过的。
分享一个小习惯,也是我个人的保命技能——写脚本的时候,凡是要删数据、清表、drop的操作,一律先做个临时备份,哪怕只是mysqldump单表也行。别嫌麻烦,这一步可能就让你从“事故现场”变成“虚惊一场”。记得有一次,我手动清理测试环境的脏数据,本来想删一批旧日志,手滑把条件写错了,差点把整个用户表清空。还好执行前习惯性备份了一下,五分钟后数据全部导回来,同事压根不知道发生了什么。
数据库误删不可怕,可怕的是没有预案。备份、binlog、延迟从库,这三招你至少得占一样,最好全都有。真到了出事儿的时候,你会发现平时花在准备上的每一分钟,都是值得的。现在就可以去检查一下你的备份脚本跑得正不正常,binlog保留期够不够长,从库有没有配置延迟复制。没配的,找个时间补上,别等到凌晨两点的电话把你叫醒。


