TiDB 日志备份与 PITR 功能架构

本文以使用 BR 工具进行备份与恢复为例,介绍 TiDB 集群日志备份与 Point-in-time recovery (PITR) 的架构设计与流程。

架构设计

日志备份和 PITR 的架构如下:

BR log backup and PITR architecture

日志备份

日志备份的流程如下:

BR log backup process design

系统组件和关键概念:

  • local metadata:表示单 TiKV 节点备份下来的数据元信息,主要包括:local checkpoint ts、global checkpoint ts、备份文件信息。
  • local checkpoint ts (in local metadata):表示这个 TiKV 中所有小于 local checkpoint ts 的日志数据已经备份到目标存储。
  • global checkpoint ts:表示所有 TiKV 中小于 global checkpoint ts 的日志数据已经备份到目标存储。它由运行在 TiDB 中的 Coordinator 模块收集所有 TiKV 的 local checkpoint ts 计算所得,然后上报给 PD。
  • TiDB Coordinator 组件:TiDB 集群的某个节点会被选举为 Coordinator,负责收集和计算整个日志备份任务的进度 (global checkpoint ts)。该组件设计上无状态,在其故障后可以从存活的 TiDB 节点中重新选出一个节点作为 Coordinator。
  • TiKV log observer 组件:运行在 TiDB 集群的每个 TiKV 节点,负责从 TiKV 读取和备份日志数据。TiKV 节点故障的话,该节点负责备份数据范围,在 Region 重新选举后,会被其他 TiKV 节点负责,这些节点会从 global checkpoint ts 重新备份故障范围的数据。

完整的备份交互流程描述如下:

  1. BR 接收备份命令 br log start

    • 解析获取日志备份任务的 checkpoint ts(日志备份起始位置)、备份存储地址。
    • Register log backup task:在 PD 注册日志备份任务 (log backup task)。
  2. TiKV 监控日志备份任务的创建与更新。

    • Fetch log backup task:每个 TiKV 节点的 log backup observer 监听 PD 中日志备份任务的创建与更新,然后备份该节点上在备份范围内的数据。
  3. TiKV log backup observer 持续地备份 KV 变更日志。

    • Read kv change data:读取 kv 数据变更,然后保存到自定义格式的备份文件中。
    • Fetch global checkpoint ts:定期从 PD 查询 global checkpoint ts。
    • Generate local metadata:定期生成 local metadata(包含 local checkpoint ts、global checkpoint ts、备份文件信息)。
    • Upload log data & metadata:定期将日志备份数据和 local metadata 上传到备份存储中。
    • Configure GC:请求 PD 阻止未备份的数据(大于 local checkpoint ts)被 TiDB GC 机制回收掉。
  4. TiDB Coordinator 监控日志备份进度。

    • Watch backup progress:轮询所有 TiKV 节点,获取各个 Region 的备份进度 (Region checkpoint ts)。
    • Report global checkpoint ts:根据各个 Region checkpoint ts,计算整个日志备份任务的进度 (global checkpoint ts),然后上报给 PD。
  5. PD 持久化日志备份任务状态。可以通过 br log status 查询。

PITR

PITR 的流程如下:

Point-in-time recovery process design

完整的 PITR 交互流程描述如下:

  1. BR 接收恢复命令 br restore point

    • 解析获取全量备份数据地址、日志备份数据地址、恢复到的时间点。
    • 查询备份数据中恢复数据对象(database 或 table),并检查要恢复的表是否存在并符合要求。
  2. BR 恢复全量备份。

  3. BR 恢复日志备份。

    • Read backup data:读取日志备份数据,计算需要恢复的日志备份数据。
    • Fetch Region info:访问 PD,获取所有 Region 和 KV range 的对应关系。
    • Request TiKV to restore data:创建日志恢复请求,发送到对应的 TiKV,日志恢复请求包含要恢复的日志备份数据信息。
  4. TiKV 接受 BR 的恢复请求,初始化 log restore worker。

    • log restore worker 获取需要恢复的日志备份数据。
  5. TiKV 恢复日志备份数据。

    • Download KVs:log restore worker 根据日志恢复请求中要恢复的备份数据,从备份存储中下载相应的备份数据到本地。
    • Rewrite KVs:log restore worker 根据恢复集群表的 table ID 对备份数据的 kv 进行重写 —— 将原有的 kv 编码中的 table ID 替换为新创建的 table ID。对 index ID,log restore worker 也进行相同的处理。
    • Apply KVs:log restore worker 将处理好的 kv 通过 raft 接口写入 store (RocksDB) 中。
    • Report restore result:log restore worker 返回恢复结果给 BR。
  6. BR 从各个 TiKV 获取恢复结果。

    • 如果局部数据恢复因为 RegionNotFoundEpochNotMatch 等原因失败,比如 TiKV 节点故障,BR 重试恢复这些数据。
    • 如果存在备份数据不可重试的恢复失败,则恢复任务失败。
    • 全部备份数据都恢复成功后,则恢复任务成功。

日志备份文件

日志备份会产生如下类型文件:

  • {min_ts}-{uuid}.log 文件:存储备份下来的 kv 数据变更记录。其中 {min_ts} 是该文件中所有 kv 数据变更记录数对应的最小 ts;{uuid} 是生成该文件的时候随机生成的。
  • {checkpoint_ts}-{uuid}.meta 文件:每个 TiKV 节点每次上传日志备份数据时会生成一个该文件,保存本次上传的所有日志备份数据文件。其中 {checkpoint_ts} 是本节点的日志备份的 checkpoint,所有 TiKV 节点的最小的 checkpoint 就是日志备份任务最新的 checkpoint;{uuid} 是生成该文件的时候随机生成的。
  • {store_id}.ts 文件:每个 TiKV 节点每次上传日志备份数据时会使用 global checkpoint ts 更新该文件。其中 {store_id} 是 TiKV 的 store ID。
  • v1_stream_truncate_safepoint.txt 文件:保存最近一次通过 br log truncate 删除日志备份数据后,存储中最早的日志备份数据对应的 ts。

备份文件目录结构

. ├── v1 │   ├── backupmeta │   │   ├── {min_restored_ts}-{uuid}.meta │   │   ├── {checkpoint}-{uuid}.meta │   ├── global_checkpoint │   │   ├── {store_id}.ts │   ├── {date} │   │   ├── {hour} │   │   │   ├── {store_id} │   │   │   │   ├── {min_ts}-{uuid}.log │   │   │   │   ├── {min_ts}-{uuid}.log ├── v1_stream_truncate_safepoint.txt

具体示例如下:

. ├── v1 │   ├── backupmeta │   │   ├── ... │   │   ├── 435213818858112001-e2569bda-a75a-4411-88de-f469b49d6256.meta │   │   ├── 435214043785779202-1780f291-3b8a-455e-a31d-8a1302c43ead.meta │   │   ├── 435214443785779202-224f1408-fff5-445f-8e41-ca4fcfbd2a67.meta │   ├── global_checkpoint │   │   ├── 1.ts │   │   ├── 2.ts │   │   ├── 3.ts │   ├── 20220811 │   │   ├── 03 │   │   │   ├── 1 │   │   │   │   ├── ... │   │   │   │   ├── 435213866703257604-60fcbdb6-8f55-4098-b3e7-2ce604dafe54.log │   │   │   │   ├── 435214023989657606-72ce65ff-1fa8-4705-9fd9-cb4a1e803a56.log │   │   │   ├── 2 │   │   │   │   ├── ... │   │   │   │   ├── 435214102632857605-11deba64-beff-4414-bc9c-7a161b6fb22c.log │   │   │   │   ├── 435214417205657604-e6980303-cbaa-4629-a863-1e745d7b8aed.log │   │   │   ├── 3 │   │   │   │   ├── ... │   │   │   │   ├── 435214495848857605-7bf65e92-8c43-427e-b81e-f0050bd40be0.log │   │   │   │   ├── 435214574492057604-80d3b15e-3d9f-4b0c-b133-87ed3f6b2697.log ├── v1_stream_truncate_safepoint.txt