CSDN话题挑战赛第2期
参赛话题:大数据技术分享
1.为什么要做这件事?
基于公司之前的系统,使用的是三方的点餐和会员系统,本公司技术人员补充后,想对会员做更多的操作,所以,决定把会员系统替换为自主研发的系统。所以需要将会员相关的数据迁移到自己公司的数据库中。
下文中,将以“三方系统”代指三方的软件及系统。
本人所负责的很单一,就是将三方系统中的会员模块相关的数据迁移至我司数据库中,不涉及业务逻辑。
2.环境
三方系统数据库:pgsql;
我司数据库系统:mongo;
我司脚本环境:node+Angular
3.思路
由于数据量大,且无三方系统不会应为数据迁移而进行停止,也就是说在迁移数据时存在新增信息的可能,且,由于三方系统牵扯多项其他的系统修改,所以存在需要持续割接的可能。
所以,需要两个迁移手段:
- 迁移手段一:期初迁移。这个迁移方案,主要用于第一次迁移数据,且数据量会比较大;
- 迁移手段二:持续迁移。基于期初迁移之后,每天定时进行前一天到现在(某个时段内)的数据迁移;
由于数据量大且牵扯pgsql表较多,所以按功能模块进行数据迁移,比如:会员基本数据迁移、会员卡迁移、消费记录迁移…
由于pgsql存在自增主键,所以迁移手段一,主要迁移逻辑为,脚本触发模块数据迁移,
- 根据自增主键,进行数据分页循环迁移;
- 先获取分页的pgsql数据,然后判断是否等于分页数据数量,等于则继续循环标识,不等于则返回不在循环标识;
- 转化pgsql数据为mongo需要的数据格式;
- 通过bulkWrite,批量写入mongo数据;
- 循环继续;
迁移手段二,持续迁移,主要迁移逻辑为,脚本触发模块数据迁移
- 根据时间,进行数据分页循环迁移;
- 先获取分页的pgsql数据,然后判断是否等于分页数据数量,等于则继续循环标识,不等于则返回不在循环标识;
- 转化pgsql数据为mongo需要的数据格式;
- 对比mongo数据,判断是新增还是修改;
- 通过bulkWrite,批量写入/修改mongo数据;
- 循环继续;
4.准备工作
由于是三方项目,且对方没有数据库文档,所以一步一坑,那先来看看我做了哪些准备吧!
- 沟通三方,先获取到相关模块的相关数据库文档;
- 了解三方数据库存储数据及根据可视化工具(PC),对比自身系统,查看是否有遗漏的数据库文档没收到;
- 内部沟通共识数据库迁移所需要的三方数据库字段及对应的我司数据库字段,并记录;
- 验证三方数据库数据,并做记录,比如必要字段取值、字段是否有值null、"",要注意、唯一字段是否存在重复值(不要小瞧这一点,被背刺了好多次)、特殊字段格式比如:手机号、身份证、生日等等,同时,对异常数据进行统计数量,并根据异常的重要性,导出相应数据进行备份特别重要;
- 协调本司产品经理及三方系统人员,对异常信息进行解答、记录特别重要、后续的battle中用得到;
- 确定各个模块对应的数据库及各模块割接顺序具体原因请看下文;
- 开始按规划逻辑进行代码编写是的,代码编写的时间用时并不长;
- 完成迁移代码之后,做数据测试迁移并验证数据;
以上工作在执行的时候,有一个非常重要的问题,那就是,一定要做好记录,并付诸文字,及时分享给相关的内部成员。
因为,我们要有心理准备,一个没有数据库文档的三方系统,数据一定是会存在一定数量的混乱,不做好记录,迁移之后也是问题多多。不要抱有不切实际的幻想,“这么成熟的系统,怎么会数据混乱呢?”
身为程序员,我曾将分享给团队一个定律,“墨菲定律”,你能想到的坏事情,它一定会来到,或早或晚。当时我给团队内解释的是,你能想到的可能出现代码bug,如果你不去修复,那么,一定有用户会触发这个bug,或早或晚。当然,这也在我们团队内之后的日子里,被无数次的验证了。
5.验证
当进行完数据的迁移之后,一定要做数据验证。因为涉及的三方系统数据量接近9000W,所以数据验非常有必要。因此,我们设计了两个系统的数据验证方案。
主要验证的数据有以下几点:
-
数据条数是否相等,比如:会员数量、微信关注数量、会员和粉丝绑定的数量
-
随机取三方数据库pgsql数据值,对比我司mongo库中对应的数据吗,是否正确;
-
验证字段合计是否正确,比如会员积分合计、会员卡金额合计;
…
6.问题
就基于此次数据迁移,踩了一些坑,也学到很多经验,下列经验,希望可以帮助到准备割接数据的朋友们。
- 三方数据库主键是自增主键,但部分数据库last_update_time字段,并不是所有字段变动都会触发。
解决方案:通过自增主键来进行分页查询迁移
- 三方数据库存在主从库,从库设置的链接时间是30s,在大量分页之后,查询速度变慢,会导致链接数据库超时
解决方案:链接主库,注意操作,只查询,不修改
- 三方数据库部分表没有索引,但是也不适合做视图,因为数据量太大,做视图会导致浪费资源
解决方案:通过自增主键分页查询,且获取到每次分页的最大主键,查询此主键后的部分数量数据
- mongoose的aggregate聚合操作查询时,内存超过32M,导致查询失败
解决方案:aggregate聚合配合 allowDiskUse:true操作,进行将数据写入临时文件
- 大量数据异常的数据,包括但不限于:取值不规范、数据绑定错误、特定某人知道的操作太多(某个操作导致取值异于正常规范,且未注释);
解决方案:及时记录并导出相关数据,协调相关人员进行数据判断(保留/摒弃),数据清洗
- 三方系统数据库中,正式环境中存在测试数据,且测试数据不是通过正规流程产生的,对于系统运行存在认知层次的bug,比如,会员累计积分为负值、会员卡充值金额为负值等等…
解决方案:1.记录并导出相关数据,做好问题注解,2.联系相关人员,是否进行删除数据,并与已方铲平经历沟通,是否在已方一同保留这类数据
- 三方数据库各个表之间存在相同字段但代表的含义不同,此处指某一字段在很多表表示同一含义,但突然在另一个表中代表其他含义,关联到三方系统本身没有数据库说明文档,导致期初给到的文档,字段注释是一样的,导致验证三方数据库数据时,数据对不上
解决方案:将自己的查询语句发到群中,咨询三方开发人员是否查询语句有问题?
- 同一ip高频且大量请求三方数据库,导致数据库将ip误以为是恶意攻击
解决方案:触发循环机制时,增加延迟设置,比如延迟200毫秒触发下一次循环
7.注意事项
一:在新系统中冗余三方系统中的数据的的唯一标识,方便后期进行数据查询。这个操作在后期维护阶段,为了生了很多麻烦,总有一些人认为,迁移数据将他们的数据搞坏了,这时候,就可以很方便的查询出新老系统中的差异。
二:一些有特殊含义的字段,一定要考虑清楚再进行取舍。例如会员中有一部分人关联了企业微信id,但是新系统中可能用不到,在经过一番博弈之后,还是保留了。因为他是一个其他系统的唯一标识,不一定哪里会采用。
三:异常数据做好记录,异常问题说明、数量、原始数据内容、解决方案。一定要保存好,这个记录曾经在迁移数据之后的半年里,多次挽救我。记忆深刻的一次是,财务进行会员卡余额统计,发现多了几千块钱,逐步排查之后,发现是迁移之后多了钱,而这笔钱,正好就是当时三方系统中,存在的测试数据,有两笔测试会员卡数据,金额为负值。
四:迁移数据之后,做好数据统计,每个表,原始数据多少,迁移了多少,共计多少。用于之后的复盘汇报。
8.总结
此次数据迁移,其实整体上的代码开发时间,大概占到整体时间的30%左右,主要的时间占比在于验证三方数据库数据,以及寻求如何处理这些脏数据的方案。
因为,我们有一个很严重的阻碍,三方系统的开发人员也不确定数据库中到底有多少坑,只能由我们一个一个踩。
因此,在验证三方数据阶段,经常会火冒三丈,需要一些额外的时间来平复自己波涛汹涌的心情!
数据量太大,且涉及表较多,所以,制定完善的迁移计划也是非常有必要的,将每一个先迁移某个模块,在执行某个模块,一一记录下来,会让整体操作时,更加得心应手,不至于丢三落四。
数据量过大,且涉及业务较多,所以,完善的计划、清晰的时间节点、不断同步的进度,是让团队信心满满的基石。
寄语
大胆假设、仔细验证