TiDB Lightning使用实践
TiDB-Lightning Toolset 是一套快速全量导入 SQL dump 文件到 TiDB 集群的工具集,自 2.1.0 版本起随 TiDB 发布,速度可达到传统执行 SQL 导入方式的至少 3 倍,适合在上线前用作迁移现有的大型数据库到全新的 TiDB 集群。
TiKV 是使用 RocksDB 以 KV 对的形式储存数据,这些数据会压缩成一个个 SST 格式文件。TiDB-Lightning Toolset使用新的思路,绕过SQL层,在线下将整个 SQL dump 转化为 KV 对、生成排好序的 SST 文件,然后直接用 Ingestion 推送到 RocksDB 里面。这样批量处理的方法略过 ACID 和线上排序等耗时步骤,让我们提升最终的速度。
TiDB-Lightning Toolset 包含两个组件:tidb-lightning 和 tikv-importer。Lightning 负责解析 SQL 成为 KV 对,而 Importer 负责将 KV 对排序与调度、上传到 TiKV 服务器。
TiDB Lightning 整体工作原理如下:
1在导入数据之前,tidb-lightning 会自动将 TiKV 集群切换为“导入模式” (import mode),优化写入效率并停止自动压缩。
2tidb-lightning 会在目标数据库建立架构和表,并获取其元数据。
3每张表都会被分割为多个连续的区块,这样来自大表 (200 GB+) 的数据就可以用增量方式并行导入。
4tidb-lightning 会为每一个区块准备一个“引擎文件 (engine file)”来处理键值对。tidb-lightning 会并发读取 SQL dump,将数据源转换成与 TiDB 相同编码的键值对,然后将这些键值对排序写入本地临时存储文件中。
5当一个引擎文件数据写入完毕时,tidb-lightning 便开始对目标 TiKV 集群数据进行分裂和调度,然后导入数据到 TiKV 集群。
引擎文件包含两种:数据引擎与索引引擎,各自又对应两种键值对:行数据和次级索引。通常行数据在数据源里是完全有序的,而次级索引是无序的。因此,数据引擎文件在对应区块写入完成后会被立即上传,而所有的索引引擎文件只有在整张表所有区块编码完成后才会执行导入。
6整张表相关联的所有引擎文件完成导入后,tidb-lightning 会对比本地数据源及下游集群的校验和 (checksum),确保导入的数据无损,然后让 TiDB 分析 (ANALYZE) 这些新增的数据,以优化日后的操作。同时,tidb-lightning 调整 AUTO_INCREMENT 值防止之后新增数据时发生冲突。
表的自增 ID 是通过行数的上界估计值得到的,与表的数据文件总大小成正比。因此,最后的自增 ID 通常比实际行数大得多。这属于正常现象,因为在 TiDB 中自增 ID 不一定是连续分配的。
7在所有步骤完毕后,tidb-lightning 自动将 TiKV 切换回“普通模式” (normal mode),此后 TiDB 集群可以正常对外提供服务。
如果需要导入的目标集群是 v3.x 或以下的版本,需要使用 Importer-backend 来完成数据的导入。在这个模式下,tidb-lightning 需要将解析的键值对通过 gRPC 发送给 tikv-importer 并由 tikv-importer 完成数据的导入。
基础数据准备
Mariadb
(mysql) [jian] > show tables; (mysql@) [jian] > select * from jian.jian; (mysql@) [jian] > select * from jiantb;
+----------------+ +------+------+ +------+
| Tables_in_jian | | id | name | | id |
+----------------+ +------+------+ +------+
| jian | | 1 | jian | | 1 |
| jiantb | | 2 | jian | +------+
+----------------+ | 3 | jian | 1 row in set (0.01 sec)
2 rows in set (0.01 sec) 3 rows in set (0.01 sec)
Tidb
这里已经存在一张表名为jian的表,是为了后续测试当目标端表已存在数据时会怎么
(root@) [jian] 00:04:01> select * from (root@) [jian] 00:03:59> show tables;
+----+------+ +----------------+
| id | name | | Tables_in_jian |
+----+------+ +----------------+
| 10 | jian | | jian |
| 11 | jian | +----------------+
| 12 | jian | 1 row in set (0.00 sec)
| 13 | jian |
| 14 | jian |
| 15 | jian |
| 16 | jian |
| 17 | jian |
+----+------+
8 rows in set (0.01 sec)
[tidb@localhost tidb-community-server-v5.4.0-linux-amd64]$ tar zxvf tidb-lightning-v5.4.0-linux-amd64.tar.gz -C ~/.tiup/bin/
tidb-lightning
TiDB Lightning 还支持使用 TiDB-backend 作为后端导入数据:tidb-lightning 将数据转换为 INSERT 语句,然后直接在目标集群上执行这些语句。
Local-backend:tidb-lightning 先将数据编码成键值对并排序存储在本地临时目录,然后将这些键值对以 SST 文件的形式上传到各个 TiKV 节点,然后由 TiKV 将这些 SST 文件 Ingest 到集群中。和 Importer-backend 原理相同,不过不依赖额外的 tikv-importer 组件。
Importer-backend:tidb-lightning 先将 SQL 或 CSV 数据编码成键值对,由 tikv-importer 对写入的键值对进行排序,然后把这些键值对 Ingest 到 TiKV 节点中。
TiDB-backend:tidb-lightning 先将数据编码成 INSERT 语句,然后直接在 TiDB 节点上运行这些 SQL 语句进行数据导入。
1 导入数据时目标端还有不为空的表
可以看之前的数据初始的样子我们故意在Tidb端留有一张同名且有数据的表,导入时会发生报错,这里我们可以使用 incremental-import = true来忽略已存在的数据
备份-f选项这里我们先只备份Tidb中已存在数据的那一张表
[tidb@localhost ~]$ dumpling -h 192.168.135.148 -P 3306 -u jian -p123456 -t 2 -B jian -f 'jian.jian' -o /tmp/jiandb.bak
[tidb@localhost ~]$ ls /tmp/jiandb.bak/
jian.jian.000000000.sql jian.jian-schema.sql jian-schema-create.sql metadata
[tidb@localhost ~]$ cat tidb-lightning.toml
[lightning]
level = "info"
file = "/tmp/tidb-lightning.log"
[tikv-importer]
backend = "local"
sorted-kv-dir = "/tmp/kvdir"
[mydumper]
data-source-dir = "/tmp/jiandb.bak/"
filter = ['*.*', '!mysql.*', '!sys.*', '!INFORMATION_SCHEMA.*', '!PERFORMANCE_SCHEMA.*', '!METRICS_SCHEMA.*', '!INSPECTION_SCHEMA.*'] ##这里的fileter=可以支持过滤需要导入的表
[tidb]
host = "192.168.135.148"
port = 4000
user = "root"
password = "123456"
status-port = 10080
pd-addr = "192.168.135.148:2379"
在配置文件中添加incremental-import = true之后可以发现已经可以正常导入了,之前的数据和我们新导入的数据都是存在的,“performance”的告警是因为我的备份文件和tikv的data在一块磁盘,大家在生产环境注意一下不要放在同一块磁盘否则会给性能带来下降
[tikv-importer]
backend = "local"
sorted-kv-dir = "/tmp/kvdir"
incremental-import = true
2 导入目标端不存在的表
备份-f这里我们只备份Tidb中不存在的那一张表,导入时tidb会自动创建对应的表结构
[tidb@localhost ~]$ dumpling -h 192.168.135.148 -P 3306 -u jian -p123456 -t 2 -B jian -f 'jian.jiantb' -o /tmp/jiandb.bak
3 导入表结构不同的表
在原数据库中创建一张表jiantb2只有id一列,而在tidb中创建jiantb2有id ,name两列。当导入时由于tidb库中的jiantb2表的name列有default值为null所以导入时是没有问题的可以把id列的数据顺利的导入
反过来当源端的数据库的列多于目标端时,tidb中只会导入自己已有的列,这个前提是导入时backend="local"。
4 断点续传
tidb-lightning的断点续传功能需要开启相关的设置,我这里配置的是将checkpoint信息记录在文件中,tidb还支持记录在数据库中。当tidb-lightning意外停掉时,当再次启动会取checkpoint中获取上一次的信息这样当导入大量数据时就不用担心中途因为因外失败而要重新导入的问题了。下边的截图中显示了我手动kill进行后导致tidb-lightning意外停止但是当下次启动时会触发“"reusing engines and files info from checkpoint"”,tidb的数据我们也可以看到是一直在增长的。至于checkpoint文件中记录的信息直接查看的话时不友好的但是可以发现它是一直在变化的。记录在文件中则会生成相对应的文件。如果记录在数据库中会生成相应的表来存放信息
[checkpoint]
enable = true
driver = "file"
dsn = "/tmp/tidb-lightning-checkpoint"
5 库表remap
tidb-lightning还可以源库的备份文件中的表复制到不同的数据库中去,这一点在多台机器并行使用tidb-lightning是也起到了一定的作用
[[routes]]
schema-pattern = "sbtest"
table-pattern = "sbtest1"
target-schema = "tidbsbtestdb"
target-table = "tidbsbtest1"
6 并行
我们同时可以启动多个tidb-lightning 进行并的的数据导入
7 Web页面
[tidb@localhost ~]$ tidb-lightning --server-mode --status-addr :8289
Verbose debug logs will be written to /tmp/lightning.log.2022-03-22T17.32.45+0800
访问地址:http://192.168.135.148:8289
通过web页面可以添任务,点击右上角的”+“,将配置写入之后点击submit任务就开始了
点击任务详情可以看到进度