TiDB 集群备份与恢复:BR 工具详解及实战

TiDB 集群备份恢复实战:BR 工具详解,掌握全量/增量备份恢复技巧,轻松应对大规模数据场景。

原文标题:数据库系列之TiDB备份恢复

原文作者:牧羊人的方向

冷月清谈:

BR 工具是 TiDB 集群备份恢复的利器,尤其适用于大规模数据场景。它通过外部程序向 TiKV 节点发送指令,进行分布式备份和恢复。

**备份原理:** BR 将数据备份为 SST 文件,并生成元信息文件 backupmeta。SST 文件包含有序的键值对,并以特定格式命名,包含 storeID、regionID 等信息。BR 备份支持全量备份、单库/表备份和增量备份。全量备份会扫描所有数据,增量备份则只备份自上次备份后的数据。

**恢复原理:** BR 恢复流程包括 Process 和 Ingest 两个阶段。Process 阶段创建新表,并根据备份数据改写 SST 文件的 key。Ingest 阶段将 SST 文件导入 TiKV,并进行 Region 分裂和打散,以均衡数据分布。

**使用方式:** BR 工具支持通过 SQL 语句、命令行或 Kubernetes 环境进行操作。

**SQL 方式:** TiDB 4.0.2 及以上版本支持通过 SQL 语句进行备份恢复。`BACKUP` 语句用于备份,`RESTORE` 语句用于恢复。可以指定备份目标、速率限制、并发数等参数。

**命令行方式:** 使用 `br` 命令进行操作,例如 `br backup full` 备份全集群数据,`br restore db` 恢复数据库数据。可以指定备份存储路径、速率限制等参数。

**场景示例:** 文章提供了单表数据备份到本地磁盘和从本地磁盘恢复数据的示例,并详细解释了备份和恢复过程中的日志信息和性能指标。文章最后还提到了 BR 工具的未来优化方向,例如在线恢复和降低对线上业务的影响。

怜星夜思:

1、文章提到了 BR 备份的性能影响,实际应用中如何评估和最小化这种影响?
2、BR 备份和 Mydumper 备份有什么区别?各自的优缺点是什么?
3、文章中提到了增量备份,实际操作中需要注意哪些问题?如何保证增量备份的完整性和一致性?

原文内容

BR工具用于TiDB集群的备份恢复,适合大数据量的备份恢复场景。本文简单介绍BR备份恢复原理和流程以及BR命令行的使用,并结合实际备份恢复场景加以测试验证。

TiDB集群数据的备份恢复使用Backup&Restore工具,BR工具是TiDB的命令行工具,支持在TiDB 3.1及以上版本使用,适合大数据量的备份恢复场景。

1、BR工作原理

BR的工作原理是通过外部程序将备份或恢复操作命令下发到各个TiKV节点,TiKV在收到命令后执行相应的备份或恢复操作。在一次备份或恢复中,各个TiKV节点都会有一个对应的备份路径,TiKV备份时产生的备份文件将会保存在该路径下,恢复时也会从该路径读取相应的备份文件。

1)备份文件类型
备份路径下会生成以下两种类型文件:
  • SST文件:存储TiKV备份下来的数据信息

  • backupmeta文件:存储本次备份的元信息,包括备份文件数、备份文件的Key区间、备份文件大小和备份文件Hash (sha256)值

  • backup.lock 件:用于防止多次备份到同一目录

2)SST 文件(Sorted String Table)命名格式
SST文件以 storeID_regionID_regionEpoch_keyHash_cf 的格式命名。格式名的解释如下:
  • storeID:TiKV节点编号

  • regionID:Region编号

  • regionEpoch:Region版本号

  • keyHash:Range startKey的Hash (sha256)值,确保唯一性

  • cf:RocksDB的ColumnFamily(默认为 default 或 write)

3)SSTable是一个键是有序的,存储字符串形式键值对的文件

"Sorted String Table"就如名字所言,它是一个内部包含了任意长度、排好序的键值对<key,value>集合的文件。其结构如上图所示,SSTable文件由两部分数据组成:索引和键值对数据。所有的key和value都是紧凑地存放在一起的,如果要读取某个键对应的值,需要通过索引中的key:offset来定位。

从上图可以看到,因为SSTable文件中所有的键值对<key,value>是存放到一起的,所以SSTable在序列化成文件之后,是不可变的,因为此时的SSTable就类似于一个数组一样,如果插入或者删除,需要移动一大片数据,开销比较大。顺序读取整个文件,就拿到了一个排好序的索引。如果文件很大,还可以为了加速访问而追加或者单独建立一个独立的key:offset的索引。

4)kvdb中有四个ColumnFamily:raft、lock、default 和 write:
  • raft列:用于存储各个Region的元信息。仅占极少量空间,用户可以不必关注。

  • lock列:用于存储悲观事务的悲观锁以及分布式事务的一阶段Prewrite锁。当用户的事务提交之后, lock cf中对应的数据会很快删除掉,因此大部分情况下lock cf中的数据也很少(少于1GB)。如果lock cf中的数据大量增加,说明有大量事务等待提交,系统出现了bug或者故障。

  • write列:用于存储用户真实的写入数据以及MVCC信息(该数据所属事务的开始时间以及提交时间)。当用户写入了一行数据时,如果该行数据长度小于255字节,那么会被存储write列中,否则的话该行数据会被存入到default列中。由于TiDB的非uniqu索引存储的value为空,unique索引存储的value为主键索引,因此二级索引只会占用writecf的空间。

  • defaul列:用于存储超过255字节长度的数据。
5)TiDB文档和配置中提到的GC是什么意思?

TiDB采用MVCC事务模型,并且支持了Snapshot Isolation级别的事务隔离,因此为了保证正在进行中的事务能够读取到一致的数据,所有的DELETE以及UPDATE。操作在TiDB中都不会立刻将原来的数据在物理上删除或者更改,而是为其新增一个版本,这样就保证了旧的版本仍然能被尚未结束的事务读取到。每隔一段时间TiDB会确认某个时间点之前的事务已经全部结束了,那么所有的数据在该时间点之前的版本都可以只保留最新的那一个,于是TiDB会将这个时间点通知TiKV,TiKV则会发起清理旧版本数据以回收物理空间的操作,这个操作被称作GC。

1.1 BR备份流程

BR备份的原理其实就是select *全表扫描,但是在tidb中和mydumper的区别是备份任务下推到各个tikv,由各个region的leader生成数据,完成分布式导出数据,提高了备份的吞吐能力。BR备份的数据形式是SST,可以直接保存在第三方存储如本地存储、S3等。BR备份使用的是SI(Snapshot Isolation)隔离级别,能够保证恢复到Point-in-Time状态。

  • Snapshot Isolation隔离级别

Snapshot Isolation隔离级别使用Row Version实现事务级别的读一致性,在当前事务开始时任何读操作都会基于相同的数据snapshot。当读取被其他事务修改的数据行时,读操作只会看到事务开始时的快照,在同一个事务中,对同一个数据重复读取,得到的值是相同的。在Snapshot隔离级别下,事务在修改任何数据之前,先将原始数据行复制到tempdb,创建数据行的一个原始版本(Row Version),后续其他事务的读操作都去读该复制的行版本。在Snapshot隔离级别下,读写操作不会互相阻塞,使用行版本控制能够提高事务的并发性,但是有一个明显的缺点,虽然用户读到的不是脏数据,但是数据可能正在被修改,很快就要过期。如果根据这个过期的数据做数据修改,可能会产生逻辑错误。

  • 整个备份过程由独立于TiKV的外部程序推进,基本流程如下所示:

  1. 外部程序根据用户指定备份范围下发备份命令到TiKV,这个外部程序最终会整合到TiDB中,入口是 SQL;

  2. TiKV接受备份请求后交由region leader处理,并使用一个特殊的iterator读取数据

  3. TiKV读取的数据会被组织成SST文件

  4. TiKV会把SST文件写到外部存储

  5. TIKV把执行信息汇报给外部程序

  6. 外部程序接收TiKV Streaming发过来的备份结果,并检查是否有范围没有备份到或者发生错误,如果有范围错误或者没有备份到则重试

  7. 重试是根据PD对应的leader然后下发

  8. 如果外部需要备份table或者database,除了它们的数据外,还需要备份schema

  • Iterator

由于TiDB/TiKV的事务模型是percolator(percolator模型介绍参看“Percolator和TiDB事务算法https://pingcap.com/blog-cn/percolator-and-txn/”),数据的存储需要使用3个CF,分别是default、lock和write,所以如果TiKV想把数据保存在SST中,那么起码TiKV需要扫出write和default的数据。这意味现有的iterator是不适用的,因为:它只能吐出default的key-value;它吐出的是point-in-time的数据。

在全量备份中,TiKV需要根据一个ts(称为backup_ts)扫出write和default的key-value。Iterator吐出的key需要是datakey,也就是key的第一个字节是‘z’,这是为了在恢复的时候可以直接ingest,不用rewrite key。

在增量备份中,TiKV需要扫出一段时间的增量数据,一段时间具体来说是(backup_ts, current_ts]。由于备份的保证是SI,所有增量数据可以直接通过扫write CF 中的记录即可得到。需要吐出的记录有:Put,新增的数据;Delete,删除的数据。不需要吐出的记录有:Lock,select for update写的记录,实际上没有任何数据变更;Rollback,清理由提交失败造成的垃圾数据。

  • BR备份过程中其它考虑问题
    • 性能:BR备份的全表扫描方式对线上业务或多或少会有些影响,可以考虑通过在SST上加上maxts的table property进行优化

    • 外部存储:BR备份存储通过接口对外连接到外部存储比如本地磁盘、S3等,TiKV在生成SST的时候不会直接把数据写到本地磁盘,而是先缓存到内存再写到外部存储中,这样就减少IO,提高整个备份的吞吐

    • 异常处理:BR备份期间的异常分为可恢复和不可恢复,可恢复异常包括RegionError(一般由region split/merge,not leader造成)、KeyLocked(一般由事务冲突造成)和Server is busy(一般由于TiKV太忙造成),出现这些异常时备份进度不会中断;除此之外的其它错误都是不可恢复异常,这些异常会中断备份的进度

    • 超出GC时间:也就是需要备份的数据已经被GC,一般出现在增量备份情况会导致备份不完整,出现这个错误的时候外部程序需要重新进行一次全量备份。当前默认的GC时间是10分钟,在开始备份的时候需要适当延长GC时间。

1.2 BR恢复流程

BR恢复由客户端驱动,整体流程如下:

1)Process
  • 客户端向region peers所处的TiKV发起Process请求

  • TiKV使用备份的 schema 信息创建新表

  • TiKV中的importer worker根据请求通过备份的元数据构建key-value的范围、下载SST,并依照新表ID构建Rewrite SST

2)Ingest 当客户端发现所有的TiKV准备好后,向region leader发起ingest请求 Leader通过Raft复制给follower,并依照rewrite rules和key范围分割并打散regions,各个TiKV执行ingest sst,导入结束

  • Key Rewrite

由于TiDB的数据在TiKV中保存的形式是:

Key: tablePrefix{tableID}_recordPrefixSep{rowID}
Value: [col1, col2, col3, col4]
Key: tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
Value: rowID

在Key中编码了tableID,所以我们不能直接把备份下来的SST文件不经任何处理恢复到TiKV中,否则就有可能因为tableID对不上而导致数据错乱。为了解决该问题,需要在恢复前对SST文件进行key的改写,将原有的tableID替换为新创建的tableID,同样的indexID也需要相同的处理。

  • Split & Scatter

TiKV对Region的大小是有限制的,默认为96MB,超出该阈值则需要分裂(Split)。集群刚启动时,只有少量的Region,在恢复的时候不能把所有数据都恢复到这些少量的Region中,所以需要提前将Region分裂并打散(Scatter)。由于备份SST文件是按照Region生成的,天然就有合适的大小和对应的数据范围,所以可以根据各个SST文件中的范围对集群中的Region进行分裂。分裂完成后还需要打散新分裂出来的Region,防止发生数据倾斜。

2、使用方式

BR工具可以通过SQL语句、命令行工具或者K8S环境下进行备份恢复。

2.1 通过SQL语句

在v4.0.2及以上版本的TiDB中,支持直接通过SQL语句进行备份恢复

2.1.1 Backup
BACKUP语句用于TiDB集群执行分布式备份操作。BACKUP语句使用的引擎与BR相同,但备份过程是由TiDB本身驱动,而非单独的BR工具。
  • 执行BACKUP需要SUPER权限。此外,执行备份的TiDB节点和集群中的所有TiKV节点都必须有对目标存储的读或写权限。

  • BACKUP 语句开始执行后将会加锁,直到整个备份任务完成、失败或取消。因此,执行 BACKUP 时需要准备一个持久的连接。如需取消任务,可执行 KILL TIDB QUERY 语句。

  • 一次只能执行一个BACKUP和RESTORE任务。如果TiDB server上已经在执行一个BACKUP或RESTORE语句,新的BACKUP将等待前面所有的任务完成后再执行。

1)备份数据库

BACKUP DATABASE `test` TO 'local:///home/tidb/backup/2021/02/';
+------------------------------+-----------+-----------------+---------------------+---------------------+

| Destination | Size | BackupTS | Queue Time | Execution Time |
+------------------------------+-----------+-----------------+---------------------+---------------------+

| local:///home/tidb/backup/2021/02/ | 248665063 | 416099531454472 | 2021-02-28 16:09:48 | 2021-02-28 16:09:48 |
+------------------------------+-----------+-----------------+---------------------+---------------------+

上述示例中,test数据库被备份到本地,数据以SST文件的形式存储在所有TiDB和TiKV节点的/home/tidb/backup/2020/04/目录中。输出信息:
  • Destination:目标存储的URL

  • Size:备份文件的总大小,单位为字节

  • BackupTS:创建备份时的快照TSO

  • Queue Time:BACKUP任务开始排队的时间戳(当前时区)

  • Execution Time:BACKUP任务开始执行的时间戳(当前时区)

2)备份表

BACKUP TABLE `test`.`sbtest01` TO 'local:///home/tidb/backup/sbtest01/';
BACKUP TABLE sbtest02, sbtest03, sbtest04 TO 'local:///home/tidb/backup/sbtest/';

3)备份集群

BACKUP DATABASE * TO 'local:///home/tidb/backup/full/';

注意:备份中不包含系统库(mysql.、INFORMATION_SCHEMA.、PERFORMANCE_SCHEMA.* 等)

4)性能调优
  • RATE_LIMIT来限制每个TiKV节点的平均上传速度

  • CONCURRENCY调整每个TiKV节点运行的备份线程,默认是4个

  • 在备份完成之前,BACKUP将对集群上的数据进行校验,以验证数据的正确性。如果无需进行校验,可以通过CHECKSUM选项禁用这一步骤。
BACKUP DATABASE `test` TO 'local:///usr/tidb/backup-01/'
RATE_LIMIT = 120 MB/SECOND
CONCURRENCY = 8
CHECKSUM = FALSE;

5)快照

可以指定一个时间戳、TSO或相对时间,来备份历史数据。

-- 相对时间
BACKUP DATABASE `test` TO 'local:///home/tidb/backup/hist01'
SNAPSHOT = 36 HOUR AGO;
-- 时间戳(当前时区)
BACKUP DATABASE `test` TO 'local:///home/tidb/backup/hist02'
SNAPSHOT = '2021-02-28 12:00:00';
-- TSO
BACKUP DATABASE `test` TO 'local:///home/tidb/backup/hist03'
SNAPSHOT = 415685305958400;

6)增量备份

提供 LAST_BACKUP 选项,只备份从上一次备份到当前快照之间的增量数据。

-- 时间戳(当前时区)
BACKUP DATABASE `test` TO 'local:///home/tidb/backup/hist02'
LAST_BACKUP = '2021-02-28 12:00:00';
-- TSO
BACKUP DATABASE `test` TO 'local:///home/tidb/backup/hist03'
LAST_BACKUP = 415685305958400;
2.1.2 Restore
RESTORE语句把BACKUP语句生成的备份文件恢复到TiDB集群中。RESTORE语句使用的引擎与BR相同,但恢复过程是由TiDB本身驱动,而非单独的BR工具。执行RESTORE语句前,确保集群已满足以下要求:
  • 集群处于“下线”状态,当前的 TiDB 会话是唯一在访问待恢复表的活跃 SQL 连接。

  • 执行全量恢复时,确保即将恢复的表不存在于集群中,因为现有的数据可能被覆盖,从而导致数据与索引不一致。

  • 执行增量恢复时,表的状态应该与创建备份时 LAST_BACKUP 时间戳的状态完全一致。
另外,在使用RESTORE时候还需注意以下几点:
  • RESTORE 语句开始执行后将会加锁,直到整个恢复任务完成、失败或取消。因此,执行 RESTORE 时需要准备一个持久的连接。如需取消任务,可执行 KILL TIDB QUERY 语句。

  • 一次只能执行一个 BACKUP 和 RESTORE 任务。如果 TiDB server 上已经在执行一个 BACKUP 或 RESTORE 语句,新的 RESTORE 将等待前面所有的任务完成后再执行。

  • RESTORE 只能在 "tikv" 存储引擎上使用,如果使用 "mocktikv" 存储引擎,RESTORE 操作会失败。

1)从备份文件恢复

RESTORE DATABASE * FROM 'local:///home/tidb/backup/2020/04/';
+------------------------------+-----------+----------+---------------------+---------------------+

| Destination | Size | BackupTS | Queue Time | Execution Time |
+------------------------------+-----------+----------+---------------------+---------------------+

| local:///home/tidb/backup/2021/02/ | 248665063 | 0 | 2021-02-28 17:16:55 | 2021-02-28 17:16:55 |
+------------------------------+-----------+----------+---------------------+---------------------+

1 row in set (28.961 sec)
上例中,RESTORE从SST文件读取数据,SST文件存储在所有TiDB和TiKV节点的 /home/tidb/backup/2020/04/ 目录下。输出信息:
  • Destination:读取的目标存储URL

  • Size:备份文件的总大小,单位为字节

  • BackupTS:不适用

  • Queue Time:RESTORE任务开始排队的时间戳(当前时区)

  • Execution Time:RESTORE任务开始执行的时间戳(当前时区)

2)部分恢复

RESTORE可以恢复部分数据库或部分表数据。如果备份文件中缺失了某些数据库或表,缺失的部分将被忽略。此时,RESTORE语句不进行任何操作即完成执行。

RESTORE DATABASE `test` FROM 'local:///home/tidb/backup/2021/02/';
RESTORE TABLE `test`.`sbtest01`, `test`.`sbtest02` FROM 'local:///home/tidb/backup/2021/02/';
3)性能调优
  • RATE_LIMIT :限制每个TiKV节点的平均下载速度

  • CONCURRENCY :调整每个TiKV的恢复线程,默认为128个

  • 在恢复完成之前,RESTORE将对备份文件中的数据进行校验,以验证数据的正确性。如果无需进行校验,可以通过CHECKSUM选项禁用这一步骤
RESTORE DATABASE * FROM 's3://example-bucket-2021/backup-06/'
RATE_LIMIT = 120 MB/SECOND
CONCURRENCY = 64
CHECKSUM = FALSE;

4)增量恢复

TiDB将识别备份文件属于全量备份或增量备份,然后执行对应的恢复操作,用户只需按照正确顺序进行增量恢复。

  • 假设按照如下方式创建一个备份任务:

BACKUP DATABASE `test` TO 'local:///home/tidb/full-backup'  SNAPSHOT = 413612900352000;
BACKUP DATABASE `test` TO 'local:///home/tidb/inc-backup-1' SNAPSHOT = 414971854848000 LAST_BACKUP = 413612900352000;
BACKUP DATABASE `test` TO 'local:///home/tidb/inc-backup-2' SNAPSHOT = 416353458585600 LAST_BACKUP = 414971854848000;
  • 在恢复备份时,需要采取同样的顺序:

RESTORE DATABASE * FROM 'local:///home/tidb/full-backup';
RESTORE DATABASE * FROM 'local:///home/tidb/inc-backup-1';
RESTORE DATABASE * FROM 'local:///home/tidb/inc-backup-2';
2.2 通过命令行工具

在v3.1以上的TiDB版本中,支持通过BR命令行工具进行备份恢复。

2.2.1 使用BR命令行备份集群数据

使用br backup命令来备份集群数据,可以通过添加full或table子命令来指定备份全部集群或者单个表的数据。

注:如果BR版本低于v4.0.8而备份的时间可能超过默认10分钟的tikv_gc_life_time,则需要手动调整该参数,比如调整为720h。

mysql -h${TiDBIP} -P4000 -u${TIDB_USER} ${password_str} -Nse \
"update mysql.tidb set variable_value='720h' where variable_name='tikv_gc_life_time'";

自v4.0.8起BR已经支持自适应 GC,无需手动调整tikv_gc_life_time。

1)备份全部集群数据

备份全部集群数据可以使用br backup full命令。

br backup full \
--pd "${PDIP}:2379" \
--storage "local:///tmp/backup" \
--ratelimit 120 \
--log-file backupfull.log
将所有集群数据备份到各个TiKV节点的/tmp/backup路径,同时也将备份的元信息文件 backupmeta 写到该路径下。
  • --ratelimit选项限制了每个TiKV执行备份任务的速度上限(单位MiB/s)

  • --log-file选项指定把BR的log写到backupfull.log文件中

注:在全速备份的情况下,如果备份盘和服务盘不同,在线备份会让只读线上服务的QPS下降15%~25%左右;如果备份盘和服务盘相同,备份将会和服务争夺I/O资源,这可能会让只读线上服务的QPS骤降一半以上。因此尽量禁止将在线服务的数据备份到TiKV的数据盘。

2)备份单个数据库的数据

备份集群中指定单个数据库的数据,可使用br backup db命令

br backup db \
--pd "${PDIP}:2379" \
--db test \
--storage "local:///tmp/backup" \
--ratelimit 120 \
--log-file backuptable.log

以上将数据库test备份到各个TiKV节点的/tmp/backup路径,同时也会将备份的元信息文件backupmeta写到该路径下。

3)备份单张表的数据

要备份集群中指定单张表的数据,可使用br backup table命令

br backup table \
--pd "${PDIP}:2379" \
--db test \
--table usertable \
--storage "local:///tmp/backup" \
--ratelimit 120 \
--log-file backuptable.log

以上将表test.usertable备份到各个TiKV节点的/tmp/backup路径,同时也会将备份的元信息文件backupmeta写到该路径下

4)增量备份

增量备份只需要在备份的时候指定上一次的备份时间戳--lastbackupts即可。注:增量备份需要与前一次全量备份在不同的路径下。

br backup full\
--pd ${PDIP}:2379 \
-s local:///home/tidb/backupdata/incr \
--lastbackupts ${LAST_BACKUP_TS}

以上命令会备份(LAST_BACKUP_TS, current PD timestamp]之间的增量数据,包括这段时间内的DDL。在恢复的时候,BR会先把所有DDL恢复,而后才会恢复数据。

  • 上一次备份的时间戳可以使用validate指令获取:

LAST_BACKUP_TS=`br validate decode --field="end-version" -s local:///home/tidb/backupdata`
2.2.2 使用BR命令行恢复集群数据

BR命令行恢复集群数据使用br restore命令,添加full、db或table子命令来恢复集群数据、某个数据库数据或者单个表数据。

注:如果使用本地存储,在恢复前必须将所有备份的SST文件复制到各个TiKV节点上,也就是每个TiKV节点需要有所有备份的SST文件。因为在数据恢复的时候,SST文件必须存在所有的Peer中,但是每个Peer分布的位置是随机的,事先并不知道哪个节点将读取哪个文件。使用共享存储NFS或S3可规避这个问题。

1)恢复全部备份数据

要将全部备份数据恢复到集群中来,可使用br restore full命令

br restore full \
--pd "${PDIP}:2379" \
--storage "local:///tmp/backup" \
--ratelimit 128 \
--log-file restorefull.log
以上将/tmp/backup路径中的全部备份数据恢复到集群中
  • --ratelimit选项限制了每个TiKV执行恢复任务的速度上限(单位MiB/s)

  • --log-file选项指定把BR的log写到restorefull.log文件中

2)恢复单个数据库的数据

要将备份数据中的某个数据库恢复到集群中,可以使用br restore db命令

br restore db \
--pd "${PDIP}:2379" \
--db "test" \
--storage "local:///tmp/backup" \
--log-file restorefull.log

以上将/tmp/backup路径中备份数据中的某个数据库恢复到集群中

3)恢复单张表的数据

要将备份数据中的某张数据表恢复到集群中,可以使用br restore table命令

br restore table \
--pd "${PDIP}:2379" \
--db "test" \
--table "usertable" \
--storage "local:///tmp/backup" \
--log-file restorefull.log

以上将/tmp/backup路径下的备份数据中的某个数据表恢复到集群中

4)增量恢复

增量恢复的方法和使用BR进行全量恢复的方法并无差别。需要注意,恢复增量数据的时候,需要保证备份时指定的last backup ts之前备份的数据已经全部恢复到目标集群。

3、BR备份与恢复场景示例

1)备份前的准备工作

对于TiDB v4.0.7及以下版本,需要在BR备份前后手动设置GC:

mysql> SELECT * FROM mysql.tidb WHERE VARIABLE_NAME = 'tikv_gc_life_time';
+-------------------+----------------+----------------------------------------------------------------------------------------+

| VARIABLE_NAME | VARIABLE_VALUE | COMMENT |
+-------------------+----------------+----------------------------------------------------------------------------------------+

| tikv_gc_life_time | 10m0s | All versions within life time will not be collected by GC, at least 10m, in Go format. |
+-------------------+----------------+----------------------------------------------------------------------------------------+

1 row in set (0.01 sec)
#更新tikv_gc_life_time
UPDATE mysql.tidb SET VARIABLE_
VALUE = '720h' WHERE VARIABLE_NAME = 'tikv_gc_life_time';

在备份完成后,将该参数调回原来的值。

UPDATE mysql.tidb SET VARIABLE_VALUE = '10m' WHERE VARIABLE_NAME = 'tikv_gc_life_time';

2)恢复前的准备工作

运行br restore命令前,需要检查新集群,确保集群内没有同名的表。如果使用的是本地存储,还需要将所有SST文件复制到--storage指定的目录下。

3.1 将单表数据备份到本地磁盘

案例:使用br backup命令,将单表数据--db test --table tb1备份到指定的本地磁盘路径local:///home/tidb/backup_local下。

1)前置要求
  • 各个TiKV节点有单独的磁盘用来存放backupSST数据

  • backup_endpoint节点有单独的磁盘用来存放备份的backupmeta文件

  • TiKV和backup_endpoint节点需要有相同的备份目录,例如/home/tidb/backup_local

2)部署拓扑

3)运行备份

备份前在TiDB里通过“admin checksum table tab01” 获得备份的目标表 --db tango--table tab01的统计信息。统计信息示例如下:

mysql> admin checksum table tab01;
+---------+------------+---------------------+-----------+-------------+

| Db_name | Table_name | Checksum_crc64_xor | Total_kvs | Total_bytes |
+---------+------------+---------------------+-----------+-------------+

| tango | tab01 | 5022109439688970821 | 14 | 489 |
+---------+------------+---------------------+-----------+-------------+

1 row in set (0.20 sec)

运行br backup命令:

[root@tango-01 tidb-toolkit]# ./bin/br backup table --db tango --table tab01 -s local:///home/tidb/backup_local/ --pd 192.168.112.101:2379 --log-file backup_local.log
Detail BR log in backup_local.log
Table backup <----------------------------------------------------------------------------------------------------------------------------------------------------> 100.00%
Checksum <--------------------------------------------------------------------------------------------------------------------------------------------------------> 100.00%

在TiKV节点能看到备份生成的SST数据

[root@tango-centos01 backup_local]# ll
total 4
-rw-r--r--. 1 tidb tidb 1757 Feb 28 15:42 5_1029_30_80992061af3e5194c3f28a5b79d486c5e9db2feda1afb3f84b4ca229ddce9932_write.sst
drwxr-xr-x. 2 tidb tidb 6 Feb 28 15:42 localtmp

4)结果解读

查看BR备份的日志,获取此次备份的相关统计信息。在日志中搜关键字"summary",可以看到以下信息:

[2021/02/28 15:42:58.853 +08:00] [INFO] [collector.go:60] ["Table backup Success summary: total backup ranges: 1, total success: 1, total failed: 0, total take(Table backup time): 838.012261ms, total take(real time): 1.874592966s, total kv: 14, total size(Byte): 489, avg speed(Byte/s): 583.52"] ["backup checksum"=19.371814ms] ["backup fast checksum"=145.174µs] ["backup total regions"=1] [BackupTS=423231010307047425] [Size=3340]
以上日志信息中包含以下内容:
  • 备份耗时:total take(s): 1.874592966

  • 数据大小:total size(Byte/s): 489

  • 备份吞吐:avg speed(Byte/s): 583.52

  • 校验耗时:take=19.371814ms

根据上表数据可以计算得到单个TiKV实例的吞吐:avg speed(MB/s)/tikv_count

3.2 从本地磁盘恢复备份数据

案例:使用br restore命令,将单表--db tango --table tab01备份数据恢复到集群中。

1)前置要求
  • 集群中没有与备份数据相同的库表

  • 集群中各个TiKV节点有单独的磁盘用来存放要恢复的backupSST数据。

  • restore_endpoint节点有单独的磁盘用来存放要恢复的backupmeta文件。

  • 集群中TiKV和restore_endpoint节点需要有相同的备份目录,例如 /home/tidb/backup_local/

如果备份数据存放在本地磁盘,那么需要执行以下的步骤:

  • 汇总所有backupSST文件到一个统一的目录下

  • 将汇总后的backupSST文件到复制到集群的所有TiKV节点下。

  • 将backupmeta文件复制到到restore endpoint节点下

2)部署拓扑

3)运行br restore恢复

[root@tango-01 tidb-toolkit]# ./bin/br restore table --db tango --table tab01  -s local:///home/tidb/backup_local/ --pd 192.168.112.101:2379 --checksum=true --log-file restore_local.log
Detail BR log in restore_local.log
Table restore <---------------------------------------------------------------------------------------------------------------------------------------------------> 100.00%

运行恢复时,参考恢复过程中的运行指标对相关指标进行监控,以了解恢复状态。

4)结果解读

在BR日志中获取此次恢复的相关统计信息。在日志中搜关键字 "summary",可以看到以下信息:

[2021/02/28 16:13:30.773 +08:00] [INFO] [collector.go:60] ["Table restore Success summary: total restore files: 2, total success: 2, total failed: 0, total take(Table restore time): 2.411387358s, total take(real time): 2.924932554s, total kv: 4, total size(Byte): 136, avg speed(Byte/s): 56.40"] ["split region"=140.78421ms] ["restore checksum"=2.351728955s] ["restore ranges"=1] [Size=3169]
以上日志信息中包含以下内容:
  • 恢复耗时:total take(s): 2.924932554

  • 数据大小:total size(Byte): 136

  • 恢复吞吐:avg speed(Byte/s): 56.40

  • Region Split 耗时:take=140.78421ms

  • 校验耗时:take=2.351728955s
根据上表数据可以计算得到:
  • 单个TiKV实例的吞吐:avg speed(MB/s)/tikv_count

  • 单个TiKV实例的平均恢复速度:total size(MB)/(split time + restore time)/tikv_count

到这里完成了使用BR工具对TiDB集群的备份恢复操作。BR备份恢复尚有很多功能在优化改进中,比如在线恢复、备份进程对当前业务的QPS影响等等。

参考资料:

  1. https://docs.pingcap.com/zh/tidb/stable/backup-and-restore-tool

  2. https://docs.pingcap.com/zh/tidb/stable/rocksdb-overview#writestall

  3. https://www.cnblogs.com/Jack47/p/sstable-1.html

  4. https://www.cnblogs.com/ljhdo/p/5037033.html


回答“文章中提到了增量备份,实际操作中需要注意哪些问题?如何保证增量备份的完整性和一致性?”这个问题,我认为,在进行增量备份之前,需要确认 TiDB 集群的 GC 时间,避免备份数据被 GC 掉。另外,建议定期进行全量备份,以便在增量备份出现问题时进行数据恢复。

评估 BR 备份性能影响,可以先在测试环境进行模拟备份,观察 CPU、内存、磁盘 IO 等指标的变化,并与线上环境的负载情况进行对比,预估对线上业务的 QPS 影响。最小化影响的方法包括:选择低峰期备份、限制备份速率、使用更高配置的备份服务器等。

关于“文章中提到了增量备份,实际操作中需要注意哪些问题?如何保证增量备份的完整性和一致性?”这个问题,需要注意的是,增量备份依赖于上一次全量备份,如果全量备份丢失或损坏,增量备份就无法使用。因此,需要妥善保管全量备份数据。

我记得官方文档好像提过一个叫“备份 SST 文件 maxts 属性”的优化方法,说是可以减少备份对线上读的影响,具体原理不太清楚,可以去查一下。

Mydumper 备份的数据是 SQL 语句,恢复速度比 BR 慢,而且容易受到 TiDB 版本兼容性的影响。BR 备份的 SST 文件可以直接导入 TiKV,恢复速度更快,兼容性更好。

BR 备份是 TiDB 原生的备份工具,直接操作 TiKV 层的数据,备份速度更快,适合大规模数据备份。Mydumper 是 MySQL 的逻辑备份工具,备份速度较慢,但可以进行数据筛选和转换。选择哪个工具取决于具体需求和数据量大小。

除了楼上说的,还可以考虑调整备份的并发度,根据 TiKV 服务器的性能适当调整,避免过度占用资源。另外,监控 TiDB 集群的监控指标,例如 TiKV 的 CPU 使用率、磁盘 IO 延迟等,可以及时发现性能瓶颈并进行调整。

补充一下,Mydumper 备份可以用于异构数据库迁移,比如从 MySQL 迁移到 TiDB,而 BR 备份只能用于 TiDB 集群之间的数据迁移。

对于“文章中提到了增量备份,实际操作中需要注意哪些问题?如何保证增量备份的完整性和一致性?”这个问题,我的看法是,保证增量备份的完整性,需要确保备份过程中没有数据丢失或损坏。可以通过校验备份数据来验证完整性。一致性方面,需要保证增量备份的数据与上一次备份的数据保持一致,避免数据冲突或错乱。