迁移常见问题

全量数据导出导入

如何将一个运行在 MySQL 上的应用迁移到 TiDB 上?

TiDB 支持绝大多数 MySQL 语法,一般不需要修改代码。

导入导出速度慢,各组件日志中出现大量重试、EOF 错误并且没有其他错误

在没有其他逻辑出错的情况下,重试、EOF 可能是由网络问题引起的,建议首先使用相关工具排查网络连通状况。以下示例使用 iperf 进行排查:

  • 在出现重试、EOF 错误的服务器端节点执行以下命令:

    iperf3 -s
  • 在出现重试、EOF 错误的客户端节点执行以下命令:

    iperf3 -c <server-IP>

下面是一个网络连接良好的客户端节点的输出:

$ iperf3 -c 192.168.196.58 Connecting to host 192.168.196.58, port 5201 [ 5] local 192.168.196.150 port 55397 connected to 192.168.196.58 port 5201 [ ID] Interval Transfer Bitrate [ 5] 0.00-1.00 sec 18.0 MBytes 150 Mbits/sec [ 5] 1.00-2.00 sec 20.8 MBytes 175 Mbits/sec [ 5] 2.00-3.00 sec 18.2 MBytes 153 Mbits/sec [ 5] 3.00-4.00 sec 22.5 MBytes 188 Mbits/sec [ 5] 4.00-5.00 sec 22.4 MBytes 188 Mbits/sec [ 5] 5.00-6.00 sec 22.8 MBytes 191 Mbits/sec [ 5] 6.00-7.00 sec 20.8 MBytes 174 Mbits/sec [ 5] 7.00-8.00 sec 20.1 MBytes 168 Mbits/sec [ 5] 8.00-9.00 sec 20.8 MBytes 175 Mbits/sec [ 5] 9.00-10.00 sec 21.8 MBytes 183 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate [ 5] 0.00-10.00 sec 208 MBytes 175 Mbits/sec sender [ 5] 0.00-10.00 sec 208 MBytes 174 Mbits/sec receiver iperf Done.

如果输出显示网络带宽较低、带宽波动大,各组件日志中就可能出现大量重试、EOF 错误。此时你需要咨询网络服务供应商以提升网络质量。

如果输出的各指标良好,请尝试更新各组件版本。如果更新后仍无法解决问题,请移步 AskTUG 论坛寻求帮助。

不小心把 MySQL 的 user 表导入到 TiDB 了,或者忘记密码,无法登录,如何处理?

重启 TiDB 服务,配置文件中增加 -skip-grant-table=true 参数,无密码登录集群后,可以根据情况重建用户,或者重建 mysql.user 表,具体表结构搜索官网。

在 Loader 运行的过程中,TiDB 可以对外提供服务吗?

该操作进行逻辑插入,TiDB 仍可对外提供服务,但不要执行相关 DDL 操作。

如何导出 TiDB 数据?

你可以通过以下方式导出 TiDB 数据:

如何从 DB2、Oracle 数据库迁移到 TiDB?

DB2、Oracle 到 TiDB 数据迁移(增量+全量),通常做法有:

  • 使用 Oracle 官方迁移工具,如 OGG、Gateway(透明网关)、CDC(Change Data Capture)。
  • 自研数据导出导入程序实现。
  • 导出(Spool)成文本文件,然后通过 Load infile 进行导入。
  • 使用第三方数据迁移工具。

目前看来 OGG 最为合适。

用 Sqoop 批量写入 TiDB 数据,虽然配置了 --batch 选项,但还是会遇到 java.sql.BatchUpdateExecption:statement count 5001 exceeds the transaction limitation 的错误,该如何解决?

  • 在 Sqoop 中,--batch 是指每个批次提交 100 条 statement,但是默认每个 statement 包含 100 条 SQL 语句,所以此时 100 * 100 = 10000 条 SQL 语句,超出了 TiDB 的事务限制 5000 条,可以增加选项 -Dsqoop.export.records.per.statement=10 来解决这个问题,完整的用法如下:

    sqoop export \ -Dsqoop.export.records.per.statement=10 \ --connect jdbc:mysql://mysql.example.com/sqoop \ --username sqoop ${user} \ --password ${passwd} \ --table ${tab_name} \ --export-dir ${dir} \ --batch
  • 也可以选择增大 tidb 的单个事物语句数量限制,不过这个会导致内存上涨。

Dumpling 导出时引发上游数据库 OOM 或报错“磁盘空间不足”

该问题可能有如下原因:

  • 数据库主键分布不均匀,例如启用了 SHARD_ROW_ID_BITS
  • 上游数据库为 TiDB,导出表是分区表

在上述情况下,Dumpling 划分导出子范围时,会划分出过大的子范围,从而向上游发送结果过大的查询。请联系 AskTUG 社区专家获取实验版本的 Dumpling。

TiDB 有像 Oracle 那样的 Flashback Query 功能么,DDL 支持么?

有,也支持 DDL。详细参考 TiDB 历史数据回溯

在线数据同步

Syncer 架构

详细参考 解析 TiDB 在线数据同步工具 Syncer

Syncer 使用文档

详细参考 Syncer 使用文档

如何配置监控 Syncer 运行情况?

下载 Syncer Json 导入到 Grafana,修改 Prometheus 配置文件,添加以下内容:

- job_name: 'syncer_ops' # 任务名字 static_configs: - targets: ['10.10.1.1:10096'] # Syncer 监听地址与端口,通知 prometheus 拉取 Syncer 的数据。

重启 Prometheus 即可。

有没有现成的同步方案,可以将数据同步到 Hbase、Elasticsearh 等其他存储?

没有,目前依赖程序自行实现。

利用 Syncer 做数据同步的时候是否支持只同步部分表?

支持,具体参考 Syncer 使用手册 Syncer 使用文档

频繁的执行 DDL 会影响 Syncer 同步速度吗?

频繁执行 DDL 对同步速度会有影响。对于 Sycner 来说,DDL 是串行执行的,当同步遇到了 DDL,就会以串行的方式执行,所以这种场景就会导致同步速度下降。

使用 Syncer gtid 的方式同步时,同步过程中会不断更新 syncer.meta 文件,如果 Syncer 所在的机器坏了,导致 syncer.meta 文件所在的目录丢失,该如何处理?

当前 Syncer 版本的没有进行高可用设计,Syncer 目前的配置信息 syncer.meta 直接存储在硬盘上,其存储方式类似于其他 MySQL 生态工具,比如 Mydumper。因此,要解决这个问题当前可以有两个方法:

  • 把 syncer.meta 数据放到比较安全的磁盘上,例如磁盘做好 raid1;

  • 可以根据 Syncer 定期上报到 Prometheus 的监控信息来还原出历史同步的位置信息,该方法的位置信息在大量同步数据时由于延迟会可能不准确。

Syncer 下游 TiDB 数据和 MySQL 数据不一致,DML 会退出么?

  • 上游 MySQL 中存在数据,下游 TiDB 中该数据不存在,上游 MySQL 执行 UPDATEDELETE(更新/删除)该条数据的操作时,Syncer 同步过程即不会报错退出也没有该条数据。
  • 下游有主键索引或是唯一索引冲突时,执行 UPDATE 会退出,执行 INSERT 不会退出。

业务流量迁入

如何快速迁移业务流量?

我们建议通过 Syncer 工具搭建成多源 MySQL -> TiDB 实时同步环境,读写流量可以按照需求分阶段通过修改网络配置进行流量迁移,建议 DB 上层部署一个稳定的网络 LB(HAproxy、LVS、F5、DNS 等),这样直接修改网络配置就能实现无缝流量迁移。

TiDB 总读写流量有限制吗?

TiDB 读流量可以通过增加 TiDB server 进行扩展,总读容量无限制,写流量可以通过增加 TiKV 节点进行扩容,基本上写容量也没有限制。

Transaction too large 是什么原因,怎么解决?

TiDB 限制了单条 KV entry 不超过 6MB,可以修改配置文件中的 txn-entry-size-limit 配置项进行调整,最大可以修改到 120MB。

分布式事务要做两阶段提交,而且底层还需要做 Raft 复制。如果一个事务非常大,提交过程会非常慢,事务写冲突概率会增加,而且事务失败后回滚会导致不必要的性能开销。所以我们设置了 key-value entry 的总大小默认不超过 100MB。如果业务需要使用大事务,可以修改配置文件中的 txn-total-size-limit 配置项进行调整,最大可以修改到 10G。实际的大小限制还受机器的物理内存影响。

在 Google 的 Cloud Spanner 上面,也有类似的限制

如何批量导入?

导入数据的时候,可以分批插入,每批最好不要超过 1w 行。

TiDB 中删除数据后会立即释放空间吗?

DELETE,TRUNCATE 和 DROP 都不会立即释放空间。对于 TRUNCATE 和 DROP 操作,在达到 TiDB 的 GC (garbage collection) 时间后(默认 10 分钟),TiDB 的 GC 机制会删除数据并释放空间。对于 DELETE 操作 TiDB 的 GC 机制会删除数据,但不会释放空间,而是当后续数据写入 RocksDB 且进行 compact 时对空间重新利用。

Load 数据时可以对目标表执行 DDL 操作吗?

不可以,加载数据期间不能对目标表执行任何 DDL 操作,这会导致数据加载失败。

TiDB 是否支持 replace into 语法?

支持,但是 load data 不支持 replace into 语法。

数据删除后查询速度为何会变慢?

大量删除数据后,会有很多无用的 key 存在,影响查询效率。目前正在开发 Region Merge 功能,完善之后可以解决这个问题,具体看参考最佳实践中的删除数据部分。

数据删除最高效最快的方式?

在删除大量数据的时候,建议使用 Delete * from t where xx limit 5000(xx 建议在满足业务过滤逻辑下,尽量加上强过滤索引列或者直接使用主键选定范围,如 id >= 5000*n+m and id <= 5000*(n+1)+m 这样的方案,通过循环来删除,用 Affected Rows == 0 作为循环结束条件,这样避免遇到事务大小的限制。如果一次删除的数据量非常大,这种循环的方式会越来越慢,因为每次删除都是从前向后遍历,前面的删除之后,短时间内会残留不少删除标记(后续会被 GC 掉),影响后面的 Delete 语句。如果有可能,建议把 Where 条件细化。可以参考官网最佳实践

TiDB 如何提高数据加载速度?

主要有两个方面:

  • 目前已开发分布式导入工具 TiDB Lightning,需要注意的是数据导入过程中为了性能考虑,不会执行完整的事务流程,所以没办法保证导入过程中正在导入的数据的 ACID 约束,只能保证整个导入过程结束以后导入数据的 ACID 约束。因此适用场景主要为新数据的导入(比如新的表或者新的索引),或者是全量的备份恢复(先 Truncate 原表再导入)。
  • TiDB 的数据加载与磁盘以及整体集群状态相关,加载数据时应关注该主机的磁盘利用率,TiClient Error/Backoff/Thread CPU 等相关 metric,可以分析相应瓶颈。

对数据做删除操作之后,空间回收比较慢,如何处理?

可以设置并行 GC,加快对空间的回收速度。默认并发为 1,最大可调整为 tikv 实例数量的 50%。可使用 update mysql.tidb set VARIABLE_VALUE="3" where VARIABLE_NAME="tikv_gc_concurrency"; 命令来调整。