大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!
刚做DBA那阵子,我特别信任备份任务后面那个绿色对勾。
它每天按时变绿,我就当数据没事了。直到有一次恢复演练,备份导出来,数据库起来了,应用也连上了。我正准备签字,旁边一个同事多嘴问了一句:“要不要对一下数据?”
一核对,某张核心表的一批关键行,金额是错的。更让我后背发凉的是——上一次备份里,这个错就已经在了。
备份任务从来没报过失败。绿勾一直在。但数据已经悄悄地坏了很多天。
那次之后我才明白一件事:备份成功,和备份可用,是两笔账。
先把这两笔账拆清楚:
可用性——备份能不能把服务拉起来,RTO够不够短。它的敌人是流程:备份失败、脚本跑不通、恢复卡住。这些问题会“喊”,会报错,会触发告警。
正确性——拉起来的数据,是不是你要的那份。它的敌人更隐蔽:数据在没人碰的时候,自己坏了。不喊,不报错,安安静静地错下去。
多数团队在监控和演练里,只验了前一层。绿勾覆盖的是可用性,它管不了正确性。
一、数据是怎么“悄悄坏”的
这类问题有个名字,叫静默损坏。来源大致三类:
第一类,存储层的位翻转。 磁盘、控制器、固件上的偶发错误,一个比特从0变成1,页里的值就变了。
第二类,内核或异常路径上的bug。 某些边角逻辑写坏了页,但系统认为写入是成功的。
第三类,人为操作。 半截的DDL、直接改数据文件的误操作。
这三类有一个共同点:日志兜不住它们。 断电丢数据是提交语义问题,redo log能兜住。静默损坏是数据本身变了,系统却以为自己对——错误在一开始就被当成了正常写入,日志里记的也是“正确的错误”。
二、页校验和能发现坏页,但有边界
InnoDB每个数据页带一段校验值。读页的时候顺带验一遍,对不上就报坏页。这是发现静默损坏的第一道机制。
但校验和有两个明确的边界。
边界一:要读到那一页才会验。 一个页几个月没人碰,坏了也没人知道,直到哪天被读到,问题才露出来。
边界二:不是所有库都默认开着。 不少引擎的校验和默认关闭,接手一套老库,第一件事是确认它到底有没有开。
所以校验和扫描不能替代恢复演练,它只是日常巡检的一环。
三、为什么备份也跟着坏
这是最容易被忽略的一点。
物理备份是把数据文件原样拷走。坏页不在数据库里等着被修复,它已经安安稳稳地躺在备份文件里了。你以为拿到的是一份干净副本,其实坏的地方一个不少。
如果是增量备份或日志备份,问题更麻烦:损坏会沿着时间线一直传下去。 今天的增量基于昨天的全量,昨天的全量里已经有坏页,今天的增量就带着它继续走。越传越深,越晚发现,可恢复的干净时间点越少。
“备份成功”和“数据可恢复”之间,隔着一次真的验证。
四、怎么验才算数
行数对得上,不代表内容对得上。金额被截断、状态映射错,条数照样一条不差。
三层比对,从粗到细:
第一层:行数与主键范围。 快,但最粗。它只能发现“少了”或“多了”,发现不了“错了”。
第二层:字段级指纹。 把关键字段拼起来算一个校验值,主从比、新旧比。金额、状态、时间戳这些容易出问题的字段,全部纳入指纹:
sql
SELECT COUNT(*) AS rows,
BIT_XOR(CRC32(CONCAT_WS('#', id, status, amount, updated_at))) AS fingerprint
FROM t_order;
指纹对不上,说明内容有差异;指纹对上了,基本可以排除字段级的静默损坏。
第三层:抽样明细。 指纹对不上时,抽样定位到具体是哪些行、哪个字段、从哪个时间点开始不对。
五、避坑清单
第一条:别把备份任务的“成功”当成数据安全的证明。 成功只覆盖了文件写出来这一步。数据对不对、能不能恢复,它一个字都没说。
第二条:恢复演练必须验数据本身,不能只验服务能不能启动。 “数据库起来了”和“数据是对的”是两件事。演练报告写“恢复成功”,如果没人比过数据,那等于没验。
第三条:对账只看行数,等于没对。 金额截断、状态错位,行数一条不少。至少加一步字段级指纹。
六、小结
数据可靠性是两层账。可用性的账,备份任务和恢复演练能算清。正确性的账,得靠页校验和扫描、字段级指纹,还有一次次真恢复去算。这两层账最大的不同是:前一层坏了会喊,后一层坏了不说话,只会安安静静地错下去,等你自己发现。只算前一层,等于把后一层交给了运气。
小耶在手,SQL 不愁
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~