一、备份恢复概述
1.1 为什么需要备份
即使 TiDB 提供了高可用能力(多副本、自动故障转移),备份仍然不可或缺:
| 场景 | 高可用能否解决 | 备份能否解决 |
|---|---|---|
| 磁盘故障 | ✓ | - |
| 机房断电 | ✓ | - |
| 误删数据 | ✗ | ✓ |
| 应用 Bug 损坏数据 | ✗ | ✓ |
| 勒索软件 | ✗ | ✓ |
| 合规要求 | - | ✓ |
高可用解决的是硬件故障,备份解决的是人为错误和灾难。
1.2 TiDB 的备份方式
| 方式 | 工具 | 特点 | 适用场景 |
|---|---|---|---|
| 物理备份 | BR | 速度快,备份 KV 层数据 | 大数据量 |
| 逻辑备份 | Dumpling | 兼容性好,备份 SQL 文件 | 小数据量、跨版本迁移 |
| 快照备份 | BR + 外部存储 | 完整集群快照 | 灾难恢复 |
| 日志备份 + PITR | BR | 支持恢复到任意时间点 | 误操作恢复 |
二、BR 工具备份与恢复
2.1 BR 简介
BR(Backup & Restore)是 TiDB 的物理备份恢复工具,直接在 KV 层操作,速度远快于逻辑备份:
BR 工作原理:
┌─────┐ ┌─────┐ ┌─────┐
│TiKV1│ │TiKV2│ │TiKV3│
└──┬──┘ └──┬──┘ └──┬──┘
│ │ │
└────────┼────────┘
│
┌───┴───┐
│ BR │ 直接与 TiKV 通信
└───┬───┘
│
v
┌───────────────┐
│ 外部存储 │
│ (S3/NFS/本地) │
└───────────────┘
2.2 安装 BR
BR 通过 TiUP 安装:
# 安装 BR 组件
tiup install br
2.3 快照备份
# 备份到本地
br backup full \
--pd "10.0.1.11:2379" \
--storage "local:///backup/tidb/full-20240521" \
--ratelimit 128 \
--log-file backupfull.log
# 备份到 NFS
br backup full \
--pd "10.0.1.11:2379" \
--storage "nfs://10.0.3.100:/backup/tidb" \
--log-file backupfull.log
# 备份到 S3
br backup full \
--pd "10.0.1.11:2379" \
--storage "s3://backup-bucket/tidb/full-20240521" \
--send-credentials-to-tikv=true \
--log-file backupfull.log
# 只备份特定数据库
br backup db \
--pd "10.0.1.11:2379" \
--db mydb \
--storage "local:///backup/tidb/mydb-20240521"
# 只备份特定表
br backup table \
--pd "10.0.1.11:2379" \
--db mydb \
--table orders \
--storage "local:///backup/tidb/mydb-orders-20240521"
2.4 快照恢复
# 从本地恢复
br restore full \
--pd "10.0.1.11:2379" \
--storage "local:///backup/tidb/full-20240521" \
--log-file restorefull.log
# 从 S3 恢复
br restore full \
--pd "10.0.1.11:2379" \
--storage "s3://backup-bucket/tidb/full-20240521" \
--send-credentials-to-tikv=true
# 注意:BR 不支持通过 --filter 重命名数据库。
# 如需恢复到不同库名,可先用 BR 恢复到临时库,再通过 RENAME TABLE 迁移。
# 或使用 TiDB Lightning 的 "rename" 功能。
恢复注意事项:
- 恢复会覆盖目标库中的同名表
- 恢复前建议先备份当前数据
- 恢复期间集群性能会下降
2.5 备份验证
# 查看备份元数据(自动读取 backupmeta 文件)
br validate decode \
--storage "local:///backup/tidb/full-20240521"
# 校验备份完整性
br validate checksum \
--storage "local:///backup/tidb/full-20240521"
三、日志备份与 PITR
3.1 什么是 PITR
PITR(Point-In-Time Recovery)允许你将数据库恢复到任意时间点,而不仅仅是备份时刻:
时间线:
10:00 ── 全量备份
│
10:30 ── 日志备份(持续捕获变更)
│
11:00 ── 日志备份
│
11:30 ── 误操作! DROP TABLE orders
│
v
恢复目标: 恢复到 11:29:59(误操作前一秒)
── 全量备份(10:00) + 日志回放(10:00~11:29:59) = 恢复点状态
3.2 开启日志备份
# 使用 BR 命令开启日志备份(需要指定 task-name)
br log start \
--pd "10.0.1.11:2379" \
--storage "s3://backup-bucket/tidb/log-backup" \
--task-name log-backup-task
# 查看日志备份状态
br log status \
--pd "10.0.1.11:2379"
3.3 PITR 恢复
# 恢复到指定时间点
br restore point \
--pd "10.0.1.11:2379" \
--storage "s3://backup-bucket/tidb/log-backup" \
--full-backup-storage "s3://backup-bucket/tidb/full-20240521" \
--restored-ts "2024-05-21 11:29:59+0800" \
--log-file pitr-restore.log
恢复过程:
1. 从全量备份恢复到临时集群
2. 从全量备份时间点开始,重放日志到指定时间
3. 恢复完成
3.4 压缩日志备份
日志备份会持续产生数据,需要定期压缩:
br log truncate \
--pd "10.0.1.11:2379" \
--storage "s3://backup-bucket/tidb/log-backup" \
--until "2024-05-20 00:00:00+0800"
# 删除 2024-05-20 之前的日志备份
四、使用 Dumpling 逻辑备份
4.1 Dumpling 备份
# 全量逻辑备份
dumpling \
-h 10.0.1.14 \
-P 4000 \
-u root \
-B mydb \
-t 8 \
-r 200000 \
-o /data/dumpling/mydb-$(date +%Y%m%d) \
--filetype sql
# 备份到 S3
dumpling \
-h 10.0.1.14 \
-P 4000 \
-u root \
-B mydb \
--s3.region us-east-1 \
--s3.endpoint https://s3.amazonaws.com \
-o "s3://backup-bucket/dumpling/mydb"
4.2 Dumpling 恢复
逻辑备份使用 TiDB Lightning 或 mysql 客户端恢复:
# 方式一: 使用 mysql 客户端(小数据量)
mysql -h 10.0.1.14 -P 4000 -u root < /data/dumpling/mydb-schema.sql
mysql -h 10.0.1.14 -P 4000 -u root < /data/dumpling/mydb.table1.000000000.sql
# 方式二: 使用 TiDB Lightning(大数据量,推荐)
tiup tidb-lightning -config lightning-restore.toml
五、容灾方案
5.1 容灾等级
| 等级 | 方案 | RPO | RTO | 适用场景 |
|---|---|---|---|---|
| 基础 | 备份 + 恢复 | 数小时 | 数小时 | 小业务 |
| 标准 | PITR | 秒级 | 数十分钟 | 一般业务 |
| 高级 | 主备集群 | 秒级 | 分钟级 | 核心业务 |
| 金融级 | 两地三中心 | 秒级 | 分钟级 | 金融业务 |
RPO(Recovery Point Objective):允许丢失的最大数据量(以时间衡量)
RTO(Recovery Time Objective):恢复服务所需的时间
5.2 主备集群容灾
主集群 同步 备集群
┌──────────┐ TiCDC/BDR ┌──────────┐
│ TiDB │ ──────────────> │ TiDB │
│ TiKV │ 实时/近实时 │ TiKV │
│ PD │ │ PD │
└──────────┘ └──────────┘
正常: 写入主集群,实时同步到备集群
故障: 切换到备集群,备变主
搭建主备复制:
# 使用 BR 备份主集群
br backup full \
--pd "primary-pd:2379" \
--storage "s3://backup-bucket/primary-snapshot"
# 在备集群恢复
br restore full \
--pd "secondary-pd:2379" \
--storage "s3://backup-bucket/primary-snapshot"
# 使用 TiCDC 持续同步
# 注意:sink-uri 需指定具体数据库,如 mysql://root@host:4000/dbname
tiup cdc cli changefeed create \
--server=http://primary-cdc:8300 \
--sink-uri="mysql://root@secondary-tidb:4000/?time-zone=UTC" \
--changefeed-id="primary-to-secondary"
故障切换流程:
1. 确认主集群不可用
2. 停止 TiCDC 同步(确保数据一致性)
3. 将应用连接切换到备集群
4. 备集群变为主集群
5. 修复原主集群后,反向建立同步
5.3 两地三中心部署
机房 A (主) 机房 B (同城) 机房 C (异地)
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ TiDB x 2 │ │ TiDB x 1 │ │ TiDB x 1 │
│ PD x 1(L) │ │ PD x 1(F) │ │ PD x 1(F) │
│ TiKV x 2(L) │ │ TiKV x 2(F) │ │ TiKV x 1(F) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└────────────────────┼───────────────────┘
│
Raft 5 副本跨区域复制
Region 的 5 个副本分布:
Region 数据:
机房 A: 2 副本 (Leader + 1 Follower) ← 低延迟读写
机房 B: 2 副本 (Follower) ← 同城容灾
机房 C: 1 副本 (Follower) ← 异地容灾
Raft 多数派 = 3 个副本
容忍: 任意 2 个副本故障
跨机房部署的延迟考量:
同城延迟 (1-3ms): 写入需要 3/5 确认,延迟增加 1-3ms
异地延迟 (20-50ms): 如果异地也参与投票,延迟显著增加
优化方案:
- 异地副本不参与 Raft 投票(Learner 角色)
- 使用 Placement Rules 控制副本分布
5.4 基于备份的容灾
这是最简单但恢复时间最长的方案:
定期备份:
── 每天凌晨 2:00 全量备份 (BR)
── 每 5 分钟日志备份 (PITR)
恢复:
── 从最近的全量备份恢复
── 重放日志到目标时间点
── 预计恢复时间: 数据量的 10-30%
六、备份策略最佳实践
6.1 推荐备份策略
全量备份: 每周一次(或每日,视数据量而定)
日志备份: 持续开启
保留策略: 全量备份保留 4 周,日志备份保留 7 天
存储位置: 至少 2 个异地位置
定期演练: 每季度做一次恢复演练
6.2 自动化备份脚本
#!/bin/bash
# backup.sh — 自动化备份脚本
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/tidb/${BACKUP_DATE}"
LOG_FILE="/var/log/tidb-backup-${BACKUP_DATE}.log"
PD_ADDR="10.0.1.11:2379"
echo "开始全量备份: ${BACKUP_DATE}" | tee -a ${LOG_FILE}
br backup full \
--pd "${PD_ADDR}" \
--storage "local://${BACKUP_DIR}" \
--ratelimit 128 \
--log-file "${LOG_FILE}" \
2>&1
if [ $? -eq 0 ]; then
echo "备份成功: ${BACKUP_DIR}" | tee -a ${LOG_FILE}
# 删除 7 天前的备份
find /backup/tidb -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
else
echo "备份失败!" | tee -a ${LOG_FILE}
# 发送告警
# curl -X POST "https://alert-url/webhook" -d "{\"text\":\"TiDB 备份失败\"}"
fi
6.3 Cron 定时任务
# 编辑 crontab
crontab -e
# 每天凌晨 2:00 执行备份
0 2 * * * /opt/scripts/backup.sh >> /var/log/tidb-backup-cron.log 2>&1