乐趣区

关于数据库:Dumpling-导出表内并发优化丨TiDB-工具分享

李淳竹(lichunzhu),TiDB 研发工程师
SIG 组:Migrate SIG Community,次要涵盖 TiDB 数据处理工具,蕴含 TiDB 数据备份 / 导入导出,TiDB 数据变更捕捉,其余数据库数据迁徙至 TiDB 等

前言

Dumpling 是由 Go 语言编写的用于对数据库进行数据导出的工具。目前反对 MySQL 协定的数据库,并且针对 TiDB 的个性进行了优化。Go Dumpling! 让导出数据更稳固文章对 Dumpling 进阶应用进行了介绍。 本文接下来将会介绍 Dumpling 外部表内并发的优化逻辑,从而帮忙大家更粗浅地了解 Dumpling 工作原理。

为什么须要表内并发

Dumpling 外部的导出逻辑能够用生产消费者模型进行诠释。生产者线程会遍历待导出数据库表汇合,再会将生成好的导出 SQL 发送给消费者线程,由消费者线程将 SQL 执行后果格式化后写入文件。不难看出,不同消费者间能够互不烦扰地进行并发导出。

由上文较容易推导的是,待导出的数据表彼此并无分割,能够由不同消费者并发导出。但大部分业务场景中,表和表之间的数据量差别微小,很容易会呈现线程空转在一张大表的状况。因而须要将大表划分为更小的“导出单元”(后文将简称为 chunk) 以便于消费者线程并行导出,从而晋升导出速度。chunk 划分也应该保障尽可能平均,不平均的 chunk 划分与大表小表并发导出的问题相似, 会使得导出工夫加倍,并极大晋升数据库服务器内存应用

导出 MySQL 时的表内并发

那么如何将大表划分为更小且较为平均的 chunk 呢?能够想到,相比于其余类型,整型数字能够较为平均地划分为多个 limit 范畴,是个最为现实的划分形式。同时,为了保障划分的整数范畴可能命中索引,防止反复扫全表从而节约计算资源,应用的划分范畴应该为索引的第一列。由此能够失去针对 MySQL 的表内并发划分形式:

首先选取第一列为整数的索引列记为 field,依照主键、惟一索引、具备最大 Cardinality 的索引的程序进行选取,从而保障该列整型数据尽量不同。抉择好整数列后,Dumpling 通过 explain 语句粗略估算该表在限定条件下会导出的数据行数并记为 count。依据结尾指定了划分行数大小的参数 rows,能够失去 Dumpling 须要将数据划分为 count/rows 个 chunk。随后通过 select min(field), max(field) 的形式得出在限定条件下的数据中的最大最小 field 记为 max_field 与 min_field。假如在这个范畴内数据是出现大体均匀分布的,则能够求出划分步长为 d=(max_field-min_field)*rows/count。各个表内并发 chunk 通过 where 条件束缚,范畴别离为 [min_field, min_field+d), [min_field+d, min_field+2d) …

从上述实现能够看出指定 rows 后划分 chunk 并不一定为 rows 行。同时,调大 rows 将间接增大各个 chunk 的步长范畴即增大各个 chunk 的数据量。因而,如果发现 Dumpling 导出时对数据库内存耗费过大时,能够适当调小 rows 从而减小各个 chunk 的数据量。在理论导出场景中,rows 设置应较为适中:过大会耗费过多内存,且容易使并发成果不好;过小则容易导致 Dumpling 频繁向数据库申请大量数据,使导出速度降落。在目前的实际场景中,配置 –rows=200000 个别可能兼顾并发成果与导出速度。

导出 TiDB v3.0/v4.0 时的表内并发

从上文能够看出,当用户表不存在散布平均的整数索引,或者 explain 语句获取数据行数的后果不精确时,表内并发成果将大打折扣。那么,TiDB 和 Dumpling 会怎么解决这一问题呢?在 TiDB 数据库如何计算一文中,提到了 TiDB 会为表中每行数据调配一个行 ID,用 RowID 示意。该 RowID 表内惟一且能够通过 select _tidb_rowid 的形式间接从数据库中获取。因而,简略的思路是间接将 _tidb_rowid 当作上文中的整型主键,采纳雷同的形式进行 chunk 划分即可。

然而,在 TiDB 高并发写入场景最佳实际中提到,为了防止 TiDB 写入热点,TiDB 表时常会应用 AUTO_RANDOM 列或在建表时退出 SHARD_ROW_ID_BITS 参数。这些参数会使得 _tidb_rowid 列散布极其不平均,从而导致 Dumpling 导出表内并发划分 chunk 时划分不精确造成大 chunk,影响导出速度甚至引发 OOM。

在 TiDB 数据库的存储中,能够失去 TiDB 的数据映射为 KV 键值对后,以 range region 的模式存储在 TiKV 上,每个 region 保留了 [StartKey,EndKey) 范畴的数据且 TiKV 会尽量放弃每个 Region 中保留的数据不超过肯定的大小。这些个性十分有利于 Dumpling 划分平均的 chunk 数据。因而,Dumpling 通过 TiDB 的 INFORMATION_SCHEMA 库下的 TIKV_REGION_STATUS 表获取导出指标表所有 Region 的 StartKey,解码出所须要的 row_id,再应用失去 rowid 作为 WHERE 条件划分出 chunk。

从上述实现中能够看出 Dumpling 的表内并发的划分尺度为 region 大小,rows 的具体值曾经不对划分后果产生影响。然而 rows 值设置与否仍将决定 Dumpling 是否采取表内并发的形式导出 TiDB 数据库。

导出 TiDB v5.0 时的表内并发

TiDB v5.0.0 开始反对了聚簇索引来防止 TiDB 此前应用 rowid 时的回表操作,晋升写入查问速度。开启聚簇索引的表将不再有 _tidb_rowid 列。同时,在 split region 等特定场景下,region 的 StartKey 也不肯定为非法值。但上文按 region 划分的思路依然是卓有成效的办法,然而须要更好的获取 region 边界划分数据的办法。

为了解决这一问题,TiDB 在 v5.0.0 及以上版本反对了 SELECT fields FROM table TABLESAMPLE REGIONS() 语法。执行该 SQL 后,TiKV 会扫描出表波及到的每个 region 并获取第一个非法 kv 对,再将失去的数据返回给 Dumpling。例如应用该 SQL SELECT 聚簇索引的各个列时,该 SQL 会返回该表每个 REGION 中第一行聚簇索引的各列值用于平均划分 chunk。

Dumpling 后续开发计划

以下为 Dumpling 后续开发的一些打算与构想。目前 Dumpling 曾经迁徙到 tidb repo,欢送大家在 Dumpling Repo 一起交换探讨,参加开发。

  • 反对导出更多品种的源数据库 (issue#11)

一般来说,只有须要反对的数据库有对应的 database driver 或 client,比方 Oracle 数据库的 golang driver godror,都能够轻微革新导出语句和调用的 Go 代码库后就实现该数据库的导出反对。这里也欢送社区的小伙伴们参加,帮忙 Dumpling 反对导出更多类型的数据库。

  • 反对导出 Sequence(issue#61)

Dumpling 目前不反对导出 TiDB Sequence,反对该性能将使导出性能更残缺。

  • 反对 checksum 校验

Dumpling 须要反对 checksum[4] [5] 校验来保障导出数据的正确性。

  • 反对 checkpoint(issue#10)

反对 Dumpling 应用 snapshot 模式导出 TiDB 时局部导出后从断点持续导出。

联 系:channel #sig-migrate in the tidbcommunity slack workspace, you can join this channel through this invitation link。

退出移动版