断点恢复
快照恢复或日志恢复会因为一些可恢复性错误导致提前结束,例如硬盘空间占满、节点宕机等等一些突发情况。在 TiDB v7.1.0 之前,在错误被处理之后,之前恢复的进度会作废,你需要重新进行恢复。对大规模集群来说,会造成大量额外成本。
为了尽可能继续上一次的恢复,从 TiDB v7.1.0 起,备份恢复特性引入了断点恢复的功能。该功能可以在意外中断后保留上一次恢复的大部分进度。
使用场景
如果你的 TiDB 集群规模很大,无法接受恢复失败后需要重新恢复的情况,那么,你可以使用断点恢复功能重试恢复。br 工具会定期记录已恢复的分片,使得在下一次重试恢复时回到离上一次退出时较近的进度。
实现原理
断点恢复的实现原理分为快照恢复和日志恢复两部分。具体实现细节请参考实现细节。
快照恢复
快照恢复的实现原理与快照备份类似,br 工具会批量恢复一段键范围 (Region) 内的所有的 SST 文件。恢复完成后,br 工具记录下这段范围以及该范围对应的恢复集群的表 ID。断点恢复功能会定期将这些新增的相关恢复信息上传至外部存储中,从而持久化存储该恢复任务已完成的键范围。
在重试恢复时,br 工具会从外部存储读取已经恢复的键范围,并匹配相关的表 ID。在恢复过程中,会跳过与断点恢复记录的键范围重叠且对应表 ID 相同的范围。
如果在重试恢复前,你删除了某些表,那么重试恢复时新创建的表的 ID 会与之前记录在断点恢复的表 ID 不同,从而绕过使用之前的断点恢复信息,重新恢复该表,也就是说,新的 ID 的同个表可以不使用旧的 ID 的断点恢复信息,而是重新记录新 ID 对应的断点恢复信息。
由于数据采用了 MVCC(多版本并发控制)机制,带有固定 TS 的数据可以被无序且重复写入。
快照恢复在恢复库表 DDL 时添加了 ifExists
参数。对于已经存在的库表(视为已经创建完毕),br 工具会自动跳过恢复。
日志恢复
日志恢复需要按照时间顺序恢复 TiKV 节点备份下来的数据元信息 (meta-kv)。断点恢复首先会根据 meta-kv 数据为备份集群和恢复集群建立一一对应的 ID 映射关系,以确保在不同重试恢复过程中 meta-kv 的 ID 保持一致。这样,meta-kv 就具备了重新恢复的能力。
与快照备份文件不同,日志备份文件的范围可能会重叠,因此无法直接使用键范围作为恢复进度的元信息。同时,日志备份文件数量可能非常多。不过,每个日志备份文件在日志备份元信息中的位置是固定的,因此可以为每个日志备份文件指定一个日志备份元信息中唯一的位置作为恢复进度的元信息。
日志备份元信息中包含一个存放文件元信息的数组。数组中的每个文件元信息代表一个由多个日志备份文件拼接而成的文件。文件元信息记录了这些日志备份文件在拼接文件中的偏移和大小。因此,br 工具可以使用三元组 (日志备份元信息名,文件元信息数组偏移,日志备份文件数组偏移)
来唯一标识一个日志备份文件。
使用限制
断点恢复功能依赖于 GC 机制,且无法记录所有已恢复的数据,具体描述如下。
GC 会被停止
在日志恢复过程中,日志数据恢复的顺序是无序的,因此可能会出现一个 key 的删除记录优先于该 key 的写入记录恢复的情况。如果此时触发 GC,该 key 的所有数据会被删除,导致该 key 后续恢复的写入记录无法被 GC 处理。为了避免这种情况,br 命令行工具会在日志恢复过程中暂停 GC。当 br 工具中途退出后,GC 将仍然保持暂停状态。
日志恢复完成后会重新启动 GC,不需要手动启动。但如果你不想再继续恢复时,请手动开启 GC,开启方法如下:
br 工具暂停 GC 的原理是通过执行 SET config tikv gc.ratio-threshold = -1.0
,将 gc.ratio-threshold
的值设置成负数来暂停 GC。你可以通过修改 gc.ratio-threshold
的值手动开启 GC,例如执行 SET config tikv gc.ratio-threshold = 1.1
将参数重置为默认值。
部分数据需要重新恢复
在重试恢复时,部分已恢复的数据可能需要重新恢复,包括正在恢复的数据和还未被断点记录的数据。
由错误引起的退出,br 工具会在退出前将已恢复的数据元信息持久化到外部存储中,因此只有正在恢复的数据需要在下一次重试中重新恢复。
如果 br 工具进程被系统中断,那么 br 将无法把已恢复的数据元信息持久化到外部存储中。br 工具持久化已恢复的数据元信息的周期为 30 秒,因此大约最近 30 秒内的已完成恢复的数据无法持久化到外部存储,在下次重试时需要重新恢复。
不要在恢复期间修改集群数据
在恢复失败后,请避免向集群写入或删除数据、删除或创建表。由于备份数据中可能包含重命名表的 DDL 操作,断点恢复无法确认被删除的表或已存在的表是否是外部操作引起的,这会影响下次重试恢复的准确性。
实现细节
断点恢复的具体操作细节分为快照恢复和 PITR 恢复两部分。
快照恢复
在第一次执行恢复时,br 工具会在恢复集群中创建 __TiDB_BR_Temporary_Snapshot_Restore_Checkpoint
数据库,用于记录断点数据,以及这次恢复的上游集群 ID 和备份的 BackupTS。
如果恢复执行失败,你可以使用相同的命令再次执行恢复,br 工具自动从 __TiDB_BR_Temporary_Snapshot_Restore_Checkpoint
数据库中读取断点信息,并从上次中断的位置继续恢复。
当恢复执行失败后,如果你尝试将与断点记录不同的备份数据恢复到同一集群,br 工具会报错,并提示上游集群 ID 或 BackupTS 与断点记录不同。如果恢复集群已被清理,你可以手动删除 __TiDB_BR_Temporary_Snapshot_Restore_Checkpoint
数据库,然后使用其他备份重试。
PITR 恢复
PITR (Point-in-time recovery) 恢复分为快照恢复和日志恢复两个阶段。
在第一次执行恢复时,br 工具首先进入快照恢复阶段。该阶段与上述只进行快照恢复操作相同,断点数据,以及备份数据的上游集群的 ID 和备份数据的 BackupTS(即日志恢复的起始时间点 start-ts
)会被记录到 __TiDB_BR_Temporary_Snapshot_Restore_Checkpoint
数据库中。如果在此阶段恢复失败,尝试继续断点恢复时无法再调整日志恢复的起始时间点 start-ts
。
在第一次执行恢复并且进入日志恢复阶段时,br 工具会在恢复集群中创建 __TiDB_BR_Temporary_Log_Restore_Checkpoint
数据库,用于记录断点数据,以及这次恢复的上游集群 ID 和恢复的时间范围 start-ts
与 restored-ts
。如果在此阶段恢复失败,重新执行恢复命令时,你需要指定与断点记录相同的 start-ts
和 restored-ts
参数,否则 br 工具会报错,并提示上游集群 ID 或恢复的时间范围与断点记录不同。如果恢复集群已被清理,你可以手动删除 __TiDB_BR_Temporary_Log_Restore_Checkpoint
数据库,然后使用其他备份重试。
在第一次执行恢复并且进入日志恢复阶段前,br 工具会构造出在 restored-ts
时间点的上下游集群库表 ID 映射关系,并将其持久化到系统表 mysql.tidb_pitr_id_map
中,以避免库表 ID 被重复分配。如果删除 mysql.tidb_pitr_id_map
中的数据,可能会导致 PITR 恢复数据不一致。