作者介绍
刘江,伴鱼 DBA,TUG 2020 年度 MOA。
背景
伴鱼在发展初期,数据存储选择了 MongoDB 数据库,MongoDB 数据库同时也支撑了伴鱼很长一段时间的业务发展。随着伴鱼业务场景的丰富以及数据量的增长,MongoDB 在有些方面开始出现问题,比如业务对事务的要求、单表性能问题、单机的容量瓶颈和从节点请求不均衡等问题。基于以上问题,数据存储,我们选择了业界比较火的分布式 TiDB 数据库,详细介绍可见《我们为什么放弃 MongoDB 和 MySQL,选择 TiDB 》一文。 2019年,伴鱼的新业务 All In TiDB,但是历史前5年的数据都积攒在 MongoDB 数据库(集群20+,单个集群数据最大1T+,数据都是经过 zlib 压缩的),而且数据还在不断增长,这时 MongoDB 集群主要存在以下 2 个主要问题:由于我们的服务器数据盘都是 1.5T 的 nvme,某些集群很快会达到容量瓶颈
随着数据量的增长,某些集群大表,由于索引不是最优,性能问题越发明显
数据迁移架构及方案
【数据迁移架构】 异构数据库的数据迁移,在业界其实都能找到参考案例,我们的迁移架构如下图所示,主要流程步骤如下:中间件获取 MongoDB oplog,将获取的 oplog 进行解析,写入到 kafka
分段将 MongoDB 的数据全量迁移到 TiDB
数据全量迁移完后,消费 kafka 数据,将增量数据同步到 TiDB
对异构数据库两侧数据进行抽样校验
将 MongoDB 的读流量迁移到 TiDB
将 MongoDB 的写流量迁移到 TiDB
![86b1e27ffaca0a266468fa4c9dffbce2.png](https://i-blog.csdnimg.cn/blog_migrate/571d4d495918144514fb7114f1a01c74.jpeg)
写流量不能回滚
数据链路较长,存在读延时
场景一
业务表只有写入和查询,没有更新和删除操作。我们可以不采用中间件迁移的模式,这时迁移的主要流程步骤如下:设计 TiDB 表结构,梳理原表的使用场景,优化索引
业务代码实现数据库双写
分段将 MongoDB 的数据全量迁移到 TiDB
对异构数据库两侧数据进行抽样校验
业务将 MongoDB 的读流量迁移到 TiDB
业务将 MongoDB 的写流量迁移到 TiDB
设计 TiDB 表结构,梳理原表的使用场景,优化索引
根据 objectID 或者创建时间索引分段将 MongoDB 的数据全量迁移到 TiDB
根据更新时间,将增量数据同步到 TiDB
对异构数据库两侧数据进行抽样校验
业务在低峰期将 MongoDB 的读写流量迁移到 TiDB
设计 TiDB 表结构,梳理原表的使用场景,优化索引
开启中间件获取最新 MongoDB oplog,将解析的数据写入到 kafka
分段将 MongoDB 的数据全量迁移到 TiDB
数据全量迁移完后,消费 kafka 中的数据,将增量数据同步到 TiDB
对异构数据库两侧数据进行抽样校验
将 MongoDB 的读流量迁移到 TiDB
将 MongoDB 的写流量迁移到 TiDB
TiDB 表结构设计。这一步做的事情包括:业务需要梳理表上的所有功能(主要是查询),哪些可以优化,哪些可以废弃,哪些索引必须加上等等;同时业务可以优化代码,收拢写入口。最终的目标保证迁移到 TiDB 的表,在很长一段时间内不会出现性能问题。
数据迁移。这一步做的事情包括:业务代码需要兼容数据迁移过程中可能发生冲突的地方(我们参考了在线改表工具的做法);迁移脚本需要做到可以随时启停,灵活控制速度,避免迁移对线上造成压力。
对异构数据库两侧数据进行抽样校验。我们把 objectID 带入到 TiDB,同时给该字段加上索引,这样抽样校验会比较方便,等抽样校验完毕后,会把索引清理掉;我们从 MongoDB 的 objectID 中解析出机器码时间戳等信息组合出来的一个整形 id,作为 TiDB 表的主键,这样也便于我们做抽样校验;如果 MongoDB 表中有唯一键,我们不需要做任何变换,直接通过唯一键对两侧数据进行校验。
业务读流量迁移到 TiDB。业务需要加开关实现快速切换,有问题可以快速回滚。
业务写流量迁移到 TiDB。读取通常需要观察一周左右,没有问题,切写流量。
方案优缺点
在场景一中,数据迁移全程,DBA 参与的工作比较少,只需要配合研发审核 sql 质量以及数据迁移过程中可能导致的数据库压力问题。缺点是,数据迁移只局限于只有写入的场景。 在场景二中,增量数据通过脚本将满足更新时间的数据查出来进行同步,数据过大或者查询时间过长,都会导致 TiDB 数据延迟较大。如果业务读请求对数据延时有要求,那么读请求不能切换到 TiDB。 在场景三中,由于数据链路较长,对延时要求特别高的场景,也同样存在延时导致两侧数据不一致的问题。方案改进点
由于方案三可以适用上述的所有场景,所在伴鱼的后续数据迁移中,我们都采用中间件迁移的模式。为了加快数据迁移的速度,同时满足业务对延时敏感的要求,我们对方案三进行了以下改进:原先从 MongoDB 批量查询一批数据,逐条插入到 TiDB,改为每次组装一批数据插入到 TiDB。
在表数据量增长比较快的场景下,由于中间件这条链路的存在,数据同步延时不可避免。之前的做法是消费 kafka 并拼装数据后同步到 TiDB,后面改为从kafka拿到 objectID 后,去 MongoDB 主库查询数据,然后再更新到 TiDB。我们这样做的目的是,假如源端MongoDB 一条数据频繁更新,同时中间件同步到 kafka 或者消费 kafka 数据存在延时,我们也能通过 objectID 拿到的最新的数据,进一步降低数据迁移延时的问题。
原先先迁移全量数据,再消费增量数据,后面改为全量和增量数据同时迁移,迁移速度进一步提高。我们做过一个统计,在 raft_store cpu 维持在 30% 左右时,全量和增量同时进行,一天大概可以迁移 4~5 亿数据。
配套建设
数据通过中间件同步,我们通常需要部署同步 MonogDB 集群对应的中间件实例,然后确认增量数据是否同步到 kafka,最后把 kafka 地址和对应的 topic 交付给研发。由于这套部署过程还是比较繁琐的,我们也将其沉淀为平台,如下图所示。![301e41f492b340d261be987a8f0da342.png](https://i-blog.csdnimg.cn/blog_migrate/42bd3b195d394c6685136ad1737104f9.jpeg)
总结
目前,我们已经将近 3T 的 MongoDB 数据迁移到 TiDB,解决了线上部分 MongoDB 集群存在的性能风险。现有 MongoDB 集群,还承担着历史众多业务,我们会时刻监测表的性能,如果发现性能风险,我们就会迁移到 TiDB。连接用户 共建社区
扫码加入 TUG
![a3556f272024e959edcfba46e2e80810.png](https://i-blog.csdnimg.cn/blog_migrate/565be4e650e4d9759874dd448e43e69f.png)
![5f7e97cf38f45d9e7a9a2e24e1fd2a7e.gif](https://i-blog.csdnimg.cn/blog_migrate/58963afc82caa7582a32e772413f6218.gif)