迁移 MySQL 集群到 TiDB 相关问题整理

上半年我们将一个在 12 台物理服务器上运行的 16 主 16 从 MySQL 集群成功的迁移到了 TiDB 上。由于原始记录达万亿行整体数据量非常庞大,整个迁移过程充满了各种挑战。在 PingCAP 伙伴们的热心帮助下整个迁移最终顺利完成,本文将整个迁移过程中遇到的问题整理出来,希望能帮助到更多希望将业务从 MySQL 迁移到 TiDB 的朋友们。

  • 写入压力大时写入吞吐发生间歇性的抖动

TiKV 需要运行在 SSD 盘上,机械盘是难以支撑起 TiKV 这种 IO 负载密集的应用的。另外需要注意服务器的 IO scheduler 是否被设定为 noop / none,对于 SSD 和 NVME 设备来说简单的 noop 和 none 往往工作的更好。在不合理的 IO 调度器设置下当 RocksDB 发生后台 Compaction 时过高的 IO 延迟会对线上业务产生非常大的影响。

除了 IO scheduler 配置之外,集群 region 或者 leader 分布不均衡产生读写热点也可能会引起 TiDB 集群响应时间的抖动。这种现象更容易发生在新初始化后的集群中,如果集群初始化完成后立刻要接入高写入量的业务,在接入写入流量前可以先使用 region split 功能将相应表格的 region 预打散。另外在线上流量没有接入可以全速进行 leader 和 region 均衡的情况下,还可以调整 pd 上的调度限制阈值来加快调度速度让集群尽快进入均衡状态。

  • TiDB 使用非聚簇索引组织数据

MySQL 中常用的 InnoDB 和 TokuDB 引擎都是采用聚簇索引的方式将主键同数据存储在一起的。当主键是由数个列组成的联合索引时,在 TiDB 的存储模式下主键部分的数据会分别在主键索引和数据中同时存在。如果主键尺寸较大那么同 MySQL 相比我们需要为 TiDB 预留更多的存储空间。

  • 大量数据导入 TiDB 时如何加快导入速度

大量数据初始全量导入一定要使用 Lightning,这种方式会比 DM 导入快至少一个数量级。一定要在导入开始前就规划好 TiKV 集群规模,确保目标集群拥有足够的空间可以容纳下 3 副本的数据规模。在开始使用 Lightning 导入全量数据之前先开启 DM 并确保 DM Worker 节点的磁盘空间可以容纳的下 Lightning 导入过程中所产生的增量 binlog。在使用 Lightning 导入初始数据完成后开启 DM 将增量数据从 MySQL 实时同步到 TiDB 中

  • 大量数据的删除 GC 速度慢且资源消耗大

TiDB 3.0 中的分布式 GC 增加了 GC 的吞吐,但逻辑数据删除的方式在 RocksDB 引擎上会产生写入压力消耗大量的资源。如果条件允许可以使用 truncate table 或者 partition 的方式快速删除数据,这时 TiKV 可以使用 delete files in range 的方式将相应 table 或者 partition 的数据快速删除。需要注意的是由于 Titan 引擎的数据组织方式不是完全按照 key 有序排列的,目前无法支持 delete files in range 的 GC 方式。在开启 Titan 引擎的环境中 truncate table 或 partition 后空间回收会慢一些。

  • Region 数过多后频繁出现节点离线的情况

在 TiDB 3.0 之前由于 raftstore 只运行在单一线程上,大量 region 的心跳可能超出 raftstore 的处理能力导致节点被判定离线。可以通过增加服务器数量或者单机运行多个 TiKV 实例的方式来降低单一 TiKV 节点所需要管理的 region 数量规模。根据经验判断 2.1 以及更早版本的 TiDB 最好将单一 TiKV 节点管理的 region 数量控制在 3 万以内。在 TiDB 3.0 之后伴随着多线程 raftstore 的引入和 region 静默的功能,这个问题得到了很好的解决。

  • 单机部署多个 TiDB 实例

在单机上部署多个 TiDB 实例时如果指定的服务端口号发生冲突,后启动的 TiDB 进程会因为无法绑定端口而失败退出。但需要注意的是,TiDB status http 服务的端口冲突只打印错误日志并不会导致服务退出。这种情况会对 TiDB status http 接口的用户产生意想不到的影响,例如 TiDB Lightning 可能会意外的连接到错误的 TiDB 集群使用错误的 database 和 table 元信息。

  • Latency 比 MySQL 高

对 latency 敏感的 query 增加 HIGH_PRIORITY hint,TiDB 和 TiKV 会将此类查询放到独立的请求队列。对于只读类的查询还可以设定 autocommit = 1 和 tidb_low_resolution_tso = 1 来避免客户端发起 transaction 的 roundtrip 耗时以及 tidb 到 pd 请求 TSO 的 roundtrip 耗时。除此以外可以通过复用 server side 的 prepared statement 我们还可以进一步减少每次重新 prepare 的重复计算和网络上 roundtrip 的开销。

  • 在高写入吞吐的场景下 TiDB 3.0 的内存消耗比 TiDB 2.x 显著增大

TiDB 3.0 的 txn local latch 可以用来避免单机上的事务冲突,进而缓解全局事务冲突情况。然而在高写入的场景下 local latch 的内存消耗会比较大。如果业务层确认写入冲突情况很少可以通过关闭 txn-local-latches 的方式来降低内存消耗。

  • 如何加快 leader 的 region 的均衡速度以及 region merge 的速度

逐步调整 pd 的调度策略增加并发 merge 上限,同时观察调整对线上流量的影响调整到合理的设置。在 TiDB 2.1 以及之前的版本可以通过下面的参数分别设定对应类型调度任务的并发上限

leader-schedule-limit:并发 leader rebalance 调度上限

region-schedule-limit:并发 region rebalance 调度上限

replica-schedule-limit:在节点故障或下线时恢复副本任务的并发上限

merge-schedule-limit:并发 region merge 调度上限

在 TiDB 3.0 中除了上面的几个调度相关的配置之外另外增加了 store 级别的流控设定。

stores show limit:查看目前每个 store 的流控设定

stores set limit 15:设定每个 store 每分钟最多能执行的 operator 任务数量为 15

  • RocksDB 后台 Compaction 产生的 IO 过大影响到在线请求或者其它业务

可以通过设定下面的配置来限制 compaction 的 IO 速率

[rocksdb]

rate-bytes-per-sec = “300MB”

  • 在索引覆盖情况下 group by 索引内有序字段时在统计信息不准确的情况下可能会选择 hash agg 导致过高的资源消耗

官方正在计划增加对应的 hint,目前采用自己构建特定版本 TiDB 的方式强制在这种情况下使用 stream agg

  • TiDB Binlog 的写入吞吐问题

目前 TiDB Binlog drainer 节点写出 binlog 到 kafka 时为了维持全局事务顺序只会使用一个分区,而这在高写入吞吐的情况下可能会导致 Kafka 的吞吐成为系统瓶颈。官方正在计划更加完善的多分区支持方案,在官方解决方案落地前我们先通过修改 drainer 基于 database 或 table 在多个分区内均衡负载来解决写入吞吐的问题。

  • 为什么不继续使用 MySQL 分库分表的方案

迁移前 MySQL 集群 master 实例数已达 16 个,单一实例上所承载的平均记录数已达 680 亿条,运维这样的一个分库分表 MySQL 集群不论是代价还是风险都非常大。在准备迁移到 TiDB 前服务器已接近极限,需尽快扩容并再次分库分表。如果我们希望提高数据安全保障在这次调整中调整一主一从到一主两从,再进一步将目前一个实例拆成两个实例,那么我们将要运维一个接近 100 个 MySQL 实例的集群。在没有配备专职 DBA 的情况下运维这样规模 MySQL 集群的风险是我们无法承受的。不止是运维的风险,在我们线上高写入的情况下 slave 节点在业务高峰期的 lag 可能会达到数千秒,一旦发生 master 的切换业务就面临着一段时间内无法读取到最近几个小时写入数据的问题。综合考虑强一致高可用的 TiDB 是在我们的数据规模下唯一的选择。

  • 为什么不使用 nosql

早期我们尝试过为系统增加 TiKV 存储后端的支持,在原型开发完成后由于没有后续的资源投入而止步于 MySQL 单一存储后端的架构。在我们面临必须考虑新解决方案的时刻面对已经膨胀到超一万亿记录的数据规模,迁移到 TiKV 或任何一个 nosql 的系统所可能面临的风险和困难都是难以想象的。相比之下同 MySQL 兼容的 TiDB 从投入产出比上无疑是一个更好的选择。

原文:https://zhuanlan.zhihu.com/p/71849169

8赞

赞,一线实战经验。

1赞

同意!分库分表是特别反人类的一种解决问题的方案,运维难度很大。

2赞