作者:吴永健​

社会数字化、智能化的发展进程中,海量的数据带来巨大挑战,各行各业都在加速数字化转型,越来越多的企业意识到数据基础设施是成功的关键。然而,作为数据基础设施的核心,传统数据库例如 MySQL 面临性能和容量瓶颈,通过中间件实现的分库分表方案复杂度高,同时带来高昂的运维成本。作为一款企业级 数据库,TiDB 采用计算、存储分离的架构,可以根据业务需要进行弹性的扩展,应对更加实时和智能的数据应用需求。TiDB 提供 Data Migration (DM) 生态工具,帮助用户实现从 MySQL 到 TiDB 数据迁移,有效降低迁移成本和风险。



使用 DM 进行数据迁移的时候,需要执行以下操作:

1 部署 DM 集群

2 创建上游数据源(source)对象,保存数据源访问信息

3 创建(多个)数据迁移任务从数据源迁移数据到 TiDB

数据迁移任务包含全量数据迁移、增量数据复制两个阶段:

全量数据迁移:从数据源迁移对应表的表结构到 TiDB,然后读取存量数据写入到 TiDB 集群;

增量数据复制:全量数据迁移完成后,从数据源读取对应的表变更然后写入到 TiDB 集群。



注意

1 在功能验证的测试环境中的 DM-master 和 DM-worker 可以部署在同一台服务器上。

2 如进行性能相关的测试,避免采用低性能存储和网络硬件配置,防止对测试结果的正确性产生干扰。

3 如果仅验证功能,可以单机部署一个 DM-master,DM-worker 部署的数量至少是上游 MySQL 实例的数量。为了保证高可用性,建议部署更多的 DM-worker。

4 DM-worker 在 dump 和 load 阶段需要存储全量数据,因此 DM-worker 的磁盘空间需要大于需要迁移数据的总量;如果迁移任务开启了 relay log,DM-worker 也需要一定的磁盘空间来存储上游的 binlog 数据。

TiDB   DM使用实践_数据库

DM架构如上图所示,主要包括三个组件:DM-master,DM-worker 和 dmctl。

DM-master 负责管理和调度数据迁移任务的各项操作

DM-worker 负责执行具体的数据迁移任务

dmctl 是用来控制 DM 集群的命令行工具



0 DM的部署安装及准备数据源

安装方式与tidb的方式基本一致这里简略的提一下

[root​​@localhost​​​ ~]# wget ​​https://download.pingcap.org/tidb-dm-v5.4.0-linux-amd64.tar.gz​

TiDB   DM使用实践_mysql_02

[tidb​​@localhost​​ ~]$ tiup dm deploy dm-jiantest v5.4.0 ./topology-dm.yaml --user tidb

[tidb​​@localhost​​ ~]$ tiup dm display dm-jiantest

TiDB   DM使用实践_数据_03

[tidb​​@localhost​​ dm]$ tiup dmctl --master-addr 192.168.135.148:8261 operate-source create source1.yaml



1 开始数据同步

在数据同步的基础上顺便写了一下DM的几个功能的使用



1Block & Allow Table Lists 

上游数据库实例表的黑白名单过滤规则,可以用来过滤或者只迁移某些 database/table 的所有操作。

对于下边规则的的场景是有两个schema:jian1,jian2 每个schema中分别有两张表 sbtest1,sbtest2目的时是只将两个schema中的sbtest1表进行同步至Tidb的两个schema:jian1,jian2下,并且初始数据同步之后增量的操作也可以继续同步

TiDB   DM使用实践_数据_04

[tidb​​@localhost​​ dm]$ tiup dmctl --master-addr 192.168.135.148:8261 start-task dm-reptask.yaml

TiDB   DM使用实践_数据_05

查看数据同步的情况,可以看到只有sbtest1表的数据进入了Tidb端

TiDB   DM使用实践_数据库_06

TiDB   DM使用实践_mysql_07

顺便引入一个小问题,进行数据同步的表一定要有主键否则会报以下错误

 "severity": "fail",

 "short_error": "table `jian1`.`jian1_tb1` primary/unique key does not exist",

"instruction": "please set primary/unique key for the table"



2 Table routing

提供将上游 MySQL/MariaDB 实例的某些表迁移到下游指定表的功能。

注意:Schema 的匹配规则需要单独设置,用来迁移 CREATE/DROP SCHEMA xx ,这里我们分以下场景



1 将不同数据库的表同步到相同的数据库下

将schema:jian1,jian2 的表sbtest1同步到Tidb端的jian_sum的schema下

TiDB   DM使用实践_数据库_08



2将不同数据库下的表同步到相同数据库下的同一张表

这里就有两个小问题样例



1自增主键

自增主键列的类型为int 或者  自增主键列的类型为bigint,未开启ignore-checking-items: ["auto_increment_ID"]:

"severity": "fail",

"short_error": "instance mariadb-replica-jian1 table `jian1`.`sbtest1` of sharding `jian_sum`.`jian_sum_sbtest1`

                have auto-increment key id and column mapping, but type of id should be bigint"

所以这里无论自增主键列的类型为int还是bigint,只要开启了自增列的检查那么报错都会提示我们在自增主键列有问题,所以这里如果想要保留自增的关键字那么我们就只能去开启ignore-checking-items: ["auto_increment_ID"]

下图可以看到即便我们的自增列是bigint他也会报错

TiDB   DM使用实践_数据_09



2 合并表时不同表的主键列数据重复问题

"result": false,

 "msg": "[code=38032:class=dm-master:scope=internal:level=high], Message: some error occurs in dm-worker: ErrCode:10006 ErrClass:\"database\" ErrScope:\"downstream\" ErrLevel:\"high\" Message:\"file jian2.sbtest1.0000000000000.sql: execute statement failed: commit\" RawCause:\"Error 1062: Duplicate entry '1' for key 'PRIMARY'\" , Workaround: Please execute `query-status` to check status.",

这里就需要我们将主键列更换为联合主键,前提是有其他列和主键列可以构成一个唯一的键

TiDB   DM使用实践_数据_10



3 Binlog event filter

Binlog event filter 是比迁移表黑白名单更加细粒度的过滤规则,可以指定只迁移或者过滤掉某些 schema / table 的指定类型 binlog,比如 INSERT、TRUNCATE TABLE。

下图是过滤掉所有的delete操纵的一个示例

TiDB   DM使用实践_数据库_11



4DDL 支持

MySQL在数据量大了后,没有人会直接去对原表进行alter,大多数人都通过第三方工具pt-online-schema-change或者gh-ost来进行改表,以此削减改表期间对线上业务的影响。而早期的dm不支持该功能时,每次上游改完表后,由于临时表(_xxxx_new,_xxx_gho等)不在白名单里,会直接导致下游tidb丢失该DDL,引发同步异常报警。当然,如果你是全库同步,那自然不会有这个问题,但绝大多数场景下都是部分表导入到TiDB,用到了白名单功能的情况下就会导致该问题出现。而1.0.5版本后,这便不再是问题。



1 普通DDL的同步

TiDB   DM使用实践_数据库_12



2 OnlineDDL 的同步

在生产业务中执行 DDL 时,产生的锁表操作会一定程度阻塞数据库的读取或者写入。为了把对读写的影响降到最低,往往会选择 online DDL 工具执行 DDL。在使用 DM 完成 MySQL 到 TiDB 的数据迁移时,可以开启online-ddl配置,实现 DM 工具与 gh-ost 或 pt-osc 的协同。

下边使用pt-online-schema-change做一个示

对于这个pt-online-schema-change本人也是对他有一段爱恨情仇,最开始由于线上数据的直接ddl会造成大量时间的锁以及前台业务的不可能问题,尤其我们还是使用galera这个问题就又被放大了。当使用这个pt-online-schema-change我本以为得到了解脱,但是实际呢,其实们看到对于大数据量的表pt-online-schema-change所带来的代价可能更大,整个表都需要做一次中转拷贝当单表数据量10G或者百G的时候个人觉得也是一个很不友好的实现方式。所以从这一点来看是不是传统的数据库模式也接受到了挑战呢?

TiDB   DM使用实践_数据_13

5 DM Relay Log

DM (Data Migration) 工具的 relay log 由若干组有编号的文件和一个索引文件组成。这些有编号的文件包含了描述数据库更改的事件。索引文件包含所有使用过的 relay log 的文件名。

在启用 relay log 功能后,DM-worker 会自动将上游 binlog 迁移到本地配置目录(若使用 TiUP 部署 DM,则迁移目录默认为 <deploy_dir> / <relay_log>)。本地配置目录 <relay_log> 的默认值是 relay-dir,可在上游数据库配置文件中进行修改。自 v5.4.0 版本起,你可以在 DM-worker 配置文件中通过 relay-dir 配置本地配置目录,其优先级高于上游数据库的配置文件。

DM-worker 在运行过程中,会将上游 binlog 实时迁移到本地文件。DM-worker 的 sync 处理单元会实时读取本地 relay log 的 binlog 事件,将这些事件转换为 SQL 语句,再将 SQL 语句迁移到下游数据库。

可以查看指定task下的relaylog信息

[tidb@localhost dm]$ tiup dmctl --master-addr 192.168.135.148:8261 query-status tidb-replicate-mariadb

从下图我们开始指定的是111的gtid位置开始记录relaylog,当我们手动执行一条dml后源端的数据库gtid加1变为112,而我们通过query-status也可以看到relaylog的位置发生了变化,同时在source指定的relaylog文件夹中我们也可以通过mysqlbinlog去查看binlog的信息也可以看到我们对应的操作

TiDB   DM使用实践_数据库_14



6 常用维护命令

查看当前task的状态

[tidb@localhost dm]$ tiup dmctl --master-addr 192.168.135.148:8261 query-status tidb-replicate-mariadb-task4

查看当前的master和worker的状态

[tidb@localhost dm]$ tiup dmctl --master-addr 192.168.135.148:8261 list-member

删除task

[tidb@localhost dm]$ tiup dmctl --master-addr 192.168.135.148:8261 stop-task tidb-replicate-mariadb         

删除数据源

[tidb@localhost dm]$ tiup dmctl --master-addr 192.168.135.148:8261 operate-source stop mariadb-replica-jian1



总结和思考

本文大致介绍了一下Tidb DM的一些使用方法与功能介绍。Tidb DM做为一个数据迁移或者同步的工具与之前提到的TiCDC还是有些差别,目前DM的上游数据库暂时还只支持与 MySQL 协议兼容的数据库(MySQL、MariaDB、Aurora MySQL)到 TiDB 的全量数据迁移和增量数据同步。 但是TiCDC可能会更加灵活一些但是不免TiCDC会带来很大程度上的代码开发的工作。对于有需求使用TiDB的Mysql类数据库用户而言,DM还是以个很好的选择,毕竟人家原厂已经给我们做出来了,并也有了很好的功能支持。 许多公司在考虑使用新的数据库的时候一般都不会直接使用,正常而言都会有一个过渡期,那么为了这个过渡期两个问题就应运而生。



1 数据的初始化同步

首先要考虑的就是怎么将数据传输过去,当前数库表结构,字段类型,业务模型等。能否在目标数据库上能够很好的支持。在这里DM 的Table routing是一个很有价值的功能将以往可能是分库分表的数据库架构进行整合这样存储Tidb这样一个本身就是一个为了应对大数据场景而生的数据库。再搭配Block & Allow Table Lists 可以相当灵活的控制源数据的走向,为新的数据模型带来了极大的便利与可能。 对于字段类型的支持想必Tidb的工程师们也费了不少脑筋。不同种类的数据库的字段类型的支持是需要一一进行测试的,最终才会形成一套可用的map。这一点在我们自己实践的时候就有特别大的感受像oracle的long字段在进行异构数据库同步的时候那简直是噩梦一般的存在,很多工具都是不支持这种类型的数据格式的同步转换的。另外即便时支持的数据类型也要进行千万次的测试以确保万无一失并经对于某些行业一个字符或者一位精度的差异都是不可能被接受的。为了应对这些可变的因素那就免不了会有一些规则的指定与限制,当下对于DM而言还是有一些使用上的限制这里大家可以参考,这也都是可以被接受和理解的,​​https://docs.pingcap.com/zh/tidb/stable/dm-overview#%E4%BD%BF%E7%94%A8%E9%99%90%E5%88%B6​​ 但是对于我个人而言当前的支持已经不错了,技术是在发展的想必以后DM的支持也会越来越好。



2 数据的增量同步

第二个就是在过渡期线上的环境肯定还是使用旧的数据库进行业务支持,新的数据库架构进行增量数据的同步和业务功能测试架构的高可用测试等,来保证新的数据库可以良好的支撑现有的业务。 增量数据的同步也可以看到当前DM对gtid和binlog pos也都是支持的,从mysql的角度而言这样的增量同步基本上是不会造成数据的丢失的。这一点上mysql已经做的很好了Tidb在这个基础上去做数据同步的话会给大家带来信心,因为可以看到的时是市面上百分之九十五以上的MySQL的数据同步或者复制都是依赖于binglog,在这一点上的技术积累已经很坚实了。

最后对于数据一致性的方面也是在数据迁移中大家很关心的一点,毕竟数据的准确才是重中之重,数据不准确及时同步了那可能也是一堆垃圾数据。 Tidb在这一方面也提供了sync-diff-inspector 的工具当然目前也仅限也对mysql类数据库的对比,这一块本人还没有使用过,但是对于官方的一些介绍了和样例来看应该也是没有什么大问题的

这样对于一个数据迁移的基本要求和核验所涉及到的点基本上Tidb都为我们考虑到了。所以我觉得这还是一个很不错的工具的。以上都是本人的一些拙见,有不善之处还请各位看官多多包涵。