# mongodb-to-mysql **Repository Path**: reywong/mongodb-to-mysql ## Basic Information - **Project Name**: mongodb-to-mysql - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2021-03-19 - **Last Updated**: 2024-11-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 说明: + 1.该程序主要的目的是在不停服的情况下,将应用的数据库从MongoDB切换到Mysql + 2.datasysc-mongo-to-mysql:数据迁移服务,将MongoDB中的数据迁移到Mysql中,支持多线程和断点续传 + 3.mongo-to-mysql-adapter: 将MongoDB的语法适配成Mysql的语法,支持如下命令: ``` // $set $unset $push $pull $pop // $mod $inc // $exists $type $size 实现 // distinct() group() count() $elemMatch $sample $geometry // $not $geoWithin $near $nearSphere $geoIntersects $maxDistance $minDistance // $and $or $nor 实现 // $in $nin $all $regex $lg $ne $lge $gt $gte 实现 ``` > 该方案已经在国内某大型快递物流企业的网关中成功实施,上线一年多运行平稳 ## 切换思路 ![Mongodb切换成mysql.png](doc/img/mongodbToMysql.png) ## 目录 ### 1.问题概要 事件: 将EDS的数据库从Mongodb切换成Mysql. 为什么是Mongodb? 市面上(公司)对Mongodb精通的运维人员比较稀缺,遇到问题难以解决 为什么是Mysql? 免费,配合公司的使用数据库规范,统一使用Mysql ### 2.面临挑战 1.XXX作为网关和MQ代理使用,没有停机窗口 2.XXX有多个节点,上线过程中涉及到新老并行 3.系统切换失败,需要支持回退 4.切换过程中,子系统要求无感知,数据无异常 5.不了解XXX,文档不全 6.不了解MongoDB及其语法 ### 3.系统分析 ![image.png](doc/img/system.png) ### 4.修改思路 1.历史数据迁移 MongoDB中的数据如何迁移到Mysql 2.修改应用代码 如何尽量减少代码的改动,降低风险降低测试周期 3.如何分步上线 如何能无感知分步上线,并且支持回滚 #### 4.1 修改思路-数据迁移 第一步要将MongoDB的数据同步到Mysql,数据库分析如下 ![image.png](doc/img/thinking.png) 同步数据相当于将JSON拆分成列,就会面临下面的问题: 1. JSON的层级格式随意,转成mysql建表难度大 2.value的值无法判断,Mysql创建表的时候字段长度无法确定的问题 3.JSON的的字段不定,无法判断建表字段 如下: ![image.png](doc/img/josn.png) 面临切换的各种问题,决定先进行验证,看看数据质量,因为会面临不断的调整,最终选择使用Python进行验证,果然坑一个比一个深,同一个集合数据如下: ![image.png](doc/img/fenxi.png) 经过之前的可行性研究,最终决定另想思路。 此时Mysql5.6以后的版本已经开始支持JSON格式了,所以打算验证该方案的可行性,需要解决两个问题: 1.JSON对象查询的效率如何? 2. Mysql存储成JSON对象如何创建索引? 做了如下优化: 1. 将_id(MongoDB内置对象)映射成虚拟字段,并创建索引 2. 将MongoDB中的索引字段映射成虚拟字段,并创建索引 ![image.png](doc/img/table.png) #### 4.2 修改思路-代码修改 代码修改初步想法,有两种方案: 第一种方案 内容:修改所有涉及操作MongoDB的代码 优点:开发简单 缺点 :涉及范围太广,需要阅读项目代码,周期长,风险大 第二种方案 内容:使用Mysql语法重写MongoDB的驱动 优点:涉及范围小不用关心调用代码,周期短,风险小 缺点:开发难度较大 由于XXX项目出问题影响较大,为了后期测试能全覆盖,最终选择了第二种方案 方案如下: + 1.重写mongodb驱动MongoDBTemplate ![image.png](doc/img/modify.png) + 2.编写的mongodb-context.xml ![image.png](doc/img/modifyContext.png) + 3.替换原有配置(可以通过参数决定是否切换mysql,方便切换) ![image.png](doc/img/mongodbMysql.png) #### 4.3 修改思路-上线步骤 ![image.png](doc/img/online.png) 1. 序列号双写,发灰度没问题发全量 > 可并行,可回滚 2.迁移数据,切换驱动开关到Mysql-JVM配置 > 在节点没有发完之前,Manager不能做修改,可并行,可回滚 3.切换双写开关-disconf配置 > 读写Mysql,备份到MongoDB > 不能并行,需要同时切换开关 4. 去掉辅助代码 ### 5.遇到的问题 #### 5.1 遇到的问题-数据迁移 1.MongoDB数特殊格式转换 _id 字段默认为ObjectId 类型,但EDS中有覆写该字段 ![image.png](doc/img/5.1.1.png) 2.添加索引麻烦 需要添加虚拟字段映射到JSON对应的字段 ![image.png](doc/img/5.1.2.png) 3.Date类型转换 MongoDB的Date类型需要转成String类型,格式需要和mongoDB的驱动一致,为:yyyy-MM-dd HH:mm:ss.SSS ![image.png](doc/img/5.1.3.png) 4.数据量大,需要提升同步效率 需要支持多线程和断点续传 ![image.png](doc/img/5.1.4.png) #### 5.2 遇到的问题-代码修改 1._id字段被覆写,系统类型转换错误 _id默认转成了String类型,但被覆写的_id中存在Date类型,代码在查询该字段没有特殊处理,自动转成Date类型 ![image.png](doc/img/5.2.1.png) 2.JSON中同一个Key的Value类型不一样,操作mysql的时候报类型转换错误 ![image.png](doc/img/5.2.2.png) 3.MongoTemplate自动将_id和id均属性映射成_id字段 覆写MongoTemplate的时候需要兼容 ![image.png](doc/img/5.2.3.png) 4.MongoDB读不存在的集合的时候不会报错,Mysql缺表会报错 XXX系统中有两张表在项目启动的时候会读取,而该表数据库中一直都不存在,MongoDB不会报异常,Mysql直接报错,系统无法启动 ![image.png](doc/img/5.2.4.png) #### 5.3遇到的问题-系统上线 1.测试环境没有灰度环境 ,无法验证,序列号双写直接写到了灰度库 灰度环境的序列号应该也是写到正式库 2.切换过程出现了一个覆写hashcode导致CPU飚高的问题 测试环境没有使用缓存,实施环境并发不够,均没有复现 3.序列号双写切换主库失败问题 思路:配置节点数,当切换的时候,会计数,当前服务阻塞读取切换节点数,如果节点数和配置的参数 相等就进行同时切换,超时时间5S 过于依赖disconf下发,在5S内engine的14个节点没有全部处理完成,导致切换失败 解决:通过redis配置,所有节点读取redis的开关