第6章:把备份放进一台从未见过源数据的实例
同一个数据库里先导出再查询,几乎不能证明备份可用。最有说服力的起点,是一台拥有新数据目录、新实例身份和空业务库的目标实例。它能接触到的恢复输入只有备份字节和明确提供的工具。这样,源端现存数据无法悄悄补上备份遗漏,恢复依赖也会真实暴露。
两次恢复分别证明什么
restore导入并发期间的第一份快照,验证跨表一致性。pitr导入第二份基线,验证后续日志恢复的起点。第二份备份取得时写入器已经结束,源业务状态不再变化,因此可以直接与导入结果逐行比较。把两个目标拆开,能避免并发源持续变化导致比较参照不清楚。
基线之前执行FLUSH BINARY LOGS,让接下来要分析的变化集中在一份新的日志文件中。这个操作简化教学中的连续性问题,不消除生产跨文件恢复的要求。dump内部的坐标仍然是唯一恢复起点,不能猜测新文件总从某个固定位置开始,因为文件头和GTID事件也占据字节。
干净不是“删几张表”
一个长期使用的实例可能残留同名数据库、用户、全局变量、GTID历史和插件。仅删掉三张业务表,并不能让环境回到空白。有些残留不会马上报错,却会在回放或建立复制时产生难以解释的行为。本书直接创建新容器和匿名数据卷,使实例初始化过程可追踪。
即使如此,容器里仍有MySQL系统数据库和初始化创建的账户。我们所说干净,是没有之前运行的业务数据与事务历史依赖,而不是完全没有任何系统状态。恢复账本不包括迁移生产账户体系,不能因root能够查询就宣布应用权限正确。真实应用恢复还应使用实际服务账户验证最小权限。
先确认过程,再确认结果
导入客户端非零退出必须立即中止。忽略中途错误继续执行,可能让前面的表存在、后面的表缺失,最后由一条成功SELECT掩盖整体失败。我们的feed以check=True等待整个输入结束,任何错误都会抛出异常,实验不会继续把部分数据当成恢复基线。
过程成功之后,state函数读取所有订单,检查分录数量等于订单数量,检查不存在孤立分录或金额不匹配,再检查余额与分录和。完整订单按主键排序,统一用制表符与换行生成规范表示,最后加入余额和分录和计算SHA-256。小数据集保留原始行,便于读者独立核查摘要的语义。
这个规范只适用于本书字段类型。生产存在NULL、二进制值、字符集和浮点数时,必须设计无歧义编码。直接拼接字符串可能把不同记录合成同一个表示。大表还需处理排序代价和并发变化,通常应在冻结或同一一致视图下核对。摘要算法再强,也不能补偿含糊的数据编码。
恢复成功之后先别开放写入
刚恢复出的数据可能只是历史快照,还要继续应用binlog。如果应用提前连接并产生新事务,目标数据就混入了恢复流程之外的变化。后续重复主键、金额差异和GTID集合问题会更难解释。本书pitr实例只接受程序安排的恢复输入,没有任何业务客户端连接。
生产可以用网络隔离和权限收口保持恢复环境封闭,完成验收后再切换入口。read_only是一层限制,但拥有管理权限的用户仍可能改变它,不能把一个变量视为所有访问边界。流程应同时说明谁能连接、谁能改设置、何时允许应用写入,以及出现差异时如何撤回。
有些缺失不会被本书样本发现
本书只有简单表结构,没有外键、分区、触发器和存储程序。虽然命令带有相关导出选项,我们没有用不存在的对象来宣称功能已测试。扩展演练时,应给每类关键对象放入能验证的行为,例如恢复后触发器是否生成审计行、应用账户是否可执行必要过程、事件调度是否按预期保持关闭或启用。
同样,备份是否加密、密钥是否可取得、压缩是否可解开,都要通过实际恢复路径证明。把配置文件里某个开关截图放进报告,只说明意图。更可靠的报告能够从备份标识一路追到恢复实例和业务验收结果,形成可重复的证据链。
一次失败的价值
如果导入需要访问源库,而源库正是故障对象,应把它视为独立恢复能力的缺口。若导入报出版本或字符集不兼容,应保留原始错误,不要手工修正到能启动后省略这些步骤。真实恢复操作可以包含修正,但它们必须版本化、可重做,并重新计入恢复时间预算。下一章会把这条原则继续应用到日志归档。