图数据库系统重构之路:从OrientDB迁移到NebulaGraph 真实案例分享

简介: 图数据库系统重构之路:从OrientDB迁移到NebulaGraph 真实案例分享

一、写在前面

读过我公众号文章的同学都知道,我做过很多次重构,可以说是“重构钉子户”,但是这次,重构图数据库OrientDB为Nebula Graph(https://www.nebula-graph.io/),可以说是我做过最艰难的一次重构,那这篇文章就来聊聊,图数据库重构之路。


二、难点在哪里

1、历史包袱重,原来使用OrientDB系统是2016年开始开发的,逻辑很复杂,历史背景完全不清楚。

2、业务不了解,我们是临时接的大数据需求,之前没有参与过这块业务,完全不了解。

3、技术栈不了解,图数据库是第一次接触(团队中也没有人了解),OrientDB和Nebula之前都没有接触过,原来老系统大部分代码是Scala语言写的,系统中使用的Hbase,Spark,Kafka对于我们也比较陌生。

4、时间紧迫

总结来说: 业务不了解,技术栈不熟悉!

tips: 大家思考一个问题,在业务和技术栈都不熟的情况下,如何做重构呢?


三、技术方案

下面介绍一下本次重构技术方案

1、背景

猎户座的图数据库OrientDB存在性能瓶颈和单点问题,需升级为Nebula。

老系统使用技术栈无法支持弹性伸缩,监控报警设施也不够完善。

2、调研事项

注: 既然业务都不熟悉,那我们都调研了哪些东西呢?

1)、对外接口梳理: 梳理系统所有对外接口,包括接口名,接口用途,请求量(QPS),平均耗时,调用方(服务和IP)

2)、老系统核心流程梳理: 输出老系统整理架构图,重要的接口(大概10个)输出流程图

3)、环境梳理: 涉及到的需要改造的项目有哪些 , 应用部署、Mysql,Redis,Hbase集群IP,及目前线上部署分支整理

4)、触发场景: 接口都是如何触发的,从业务使用场景出发,每个接口至少一个场景覆盖到,方便后期功能验证

5)、改造方案: 可行性分析,针对每一个接口,如何改造(OrientDB语句改为Nebula查询语句),入图(写流程)如何改造

6)、新系统设计方案: 输出整理架构图,核心流程图

3、项目目标

完成图数据库数据源 OrientDB改造为Nebula,重构老系统统一技术栈为Java,支持服务水平扩展。

4、整体方案

我们采用了比较激进的方案:

1、从调用接口入口出发,直接重写底层老系统,影响面可控

2、一劳永逸,方便后期维护

3、统一Java技术栈、接入公司统一服务框架,更利于监控及维护

4、基础图数据库应用边界清晰,后续上层应用接入图数据库更简单

注:这里就贴调研阶段画的图,图涉及业务,我这里就不列举了。

5、灰度方案

** 1) 灰度方案**

写请求:采用同步双写

读请求:按流量从小到大陆续迁移、平滑过渡

** 2) 灰度计划**

阶段一 阶段二 阶段三 阶段四 阶段五 阶段六 阶段七
0% 1‰ 1% 10% 20% 50% 100%
同步双写, 流量回放采样对比,100%通过、预计灰度2天 灰度2天 灰度2天 灰度5天、此阶段要压测 灰度2天 灰度2天 -

注:

  1. 1. 配置中心开关控制,有问题随时切换,秒级恢复。
  2. 2. 读接口遗漏无影响, 只有改到的才会影响。
  3. 3. 使用参数 hash值作为key,确保同一参数多次请求结果一致、满足 abs(key) % 1000 < X ( 0< X < 1000, X为动态配置 ) 即为命中灰度。

题外话: 其实重构,最重要的就是灰度方案,这个我在之前文章也提到过,本次灰度方案设计比较完善,大家重点看阶段一、在灰度放量之前,我们用线上真实的流量去异步做数据对比,对比完全通过之后,再放量,本次数据对比阶段比预期长了一些(实际上用了2周时间,发现了很多隐藏问题)。

6、数据对比方案

1) 未命中灰度流程如下:

先调用老系统,再根据是否命中采样(采样比例配置 0% ~ 100% ),命中采样会发送MQ,再在新系统消费MQ,请求新系统接口,于老系统接口返回数据进行json对比,对比不一致发送企业微信通知,实时感知数据不一致,发现并解决问题。

反之亦然!!

7、数据迁移方案

1)、 全量(历史数据):脚本全量迁移,上线期间产生不一致从MQ消费近3天数据

2)、增量:同步双写(写的接口很少,写请求QPS不高)

8、改造案例 - 以子图查询为例

1)改造前

@Override
    public MSubGraphReceive getSubGraph(MSubGraphSend subGraphSend) {
        logger.info("-----start getSubGraph------(" + subGraphSend.toString() + ")");
        MSubGraphReceive r = (MSubGraphReceive) akkaClient.sendMessage(subGraphSend, 30);
        logger.info("-----end getSubGraph:");
        return r;
    }

2)改造后

定义灰度模块接口

public interface IGrayService {
    /**
     * 是否命中灰度 配置值 0 ~ 1000  true: 命中  false:未命中
     *
     * @param hashCode
     * @return
     */
    public boolean hit(Integer hashCode);
    /**
     * 是否取样 配置值 0 ~ 100
     *
     * @return
     */
    public boolean hitSample();
    /**
     * 发送请求-响应数据
     * @param requestDTO
     */
    public void sendReqMsg(MessageRequestDTO requestDTO);
    /**
     * 根据
     * @param methodKeyEnum
     * @return
     */
    public boolean hitSample(MethodKeyEnum methodKeyEnum);
}

接口改造如下, newCoreService请求到new-core新服务,接口业务逻辑和老系统接口保持一致、底层图数据库改为查询Nebula

@Override
    public MSubGraphReceive getSubGraph(MSubGraphSend subGraphSend) {
        logger.info("-----start getSubGraph------(" + subGraphSend.toString() + ")");
        long start = System.currentTimeMillis();
        //1. 请求灰度
        boolean hit = grayService.hit(HashUtils.getHashCode(subGraphSend));
        MSubGraphReceive r;
        if (hit) {
            //2、命中灰度 走新流程
            r = newCoreService.getSubGraph(subGraphSend); // 使用Dubbo调用新服务
        } else {
            //这里是原来的流程 使用的akka通信
            r = (MSubGraphReceive) akkaClient.sendMessage(subGraphSend, 30);
        }
        long requestTime = System.currentTimeMillis() - start;
        //3.采样命中了发送数据对比MQ 
        if (grayService.hitSample(MethodKeyEnum.getSubGraph_subGraphSend)) {
            MessageRequestDTO requestDTO = new MessageRequestDTO.Builder()
                    .req(JSON.toJSONString(subGraphSend))
                    .res(JSON.toJSONString(r))
                    .requestTime(requestTime)
                    .methodKey(MethodKeyEnum.getSubGraph_subGraphSend)
                    .isGray(hit).build();
            grayService.sendReqMsg(requestDTO);
        }
        logger.info("-----end getSubGraph: {} ms", requestTime);
        return r;
    }

9、项目排期计划

投入人力: 开发4人,测试1人

主要事项及耗时如下:

方案设计阶段 开发阶段 测试阶段 灰度阶段
1、流程梳理
2、画流程图、整理架构图
3、方案设计
1、新服务项目搭建,Nebula操作类ORM框架封装
2、接口改造(10多个接口改造)
3、MQ消费改造
4、数据对比工具开发(含企微通知)
5、数据迁移脚本开发
6、接口联调
7、代码组内CR
1、功能测试
2、数据对比
3、100%流量老系统回归测试
4、100%流量新系统回归测试
5、生产数据迁移

1、分7个阶段灰度,平滑过渡
2、生产数据实时对比
3、监控&报警设施完善(这个在压测之前完成,方案压测的时候观测指标)
4、压测(10%流量压测)
5、数据备份与恢复演练(采用nebula快照备份)、扩容演练
耗时1周 耗时3周 耗时2周

10、所需资源

3台Nebula机器 ,配置: 8核64G,2T SSD硬盘

6台docker服务,配置: 2核4G


四、重构收益

经过团队2个月奋斗,目前已完成灰度阶段,收益如下

1、Nebula本身支持分布式扩展,新系统服务支持弹性伸缩,整体支持性能水平扩展

2、从压测结果看,接口性能提升很明显,可支撑请求远超预期

3、接入公司统一监控、告警,更利于后期维护


五、总结

本次重构顺利完成,感谢本次一起重构的小伙伴,以及大数据、风控同学支持,同时也感谢Nebula社区(https://discuss.nebula-graph.com.cn/) ,我们遇到一些问题提问,也很快帮忙解答。

欢迎关注,不定期分享原创技术文章。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
9月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
10月前
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。
|
12月前
|
人工智能 运维 关系型数据库
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
1652 1
|
存储 关系型数据库 数据挖掘
【瑶池数据库动手活动及话题本周精选(体验ADB、 SelectDB,参与 RDS 迁移训练营)】(4.21-4.27)
本文为 “瑶池数据库动手活动及话题精选” 系列第一期,聚焦 SelectDB 日志分析、AnalyticDB Zero-ETL 集成、RDS 迁移训练营三大实战,设积分、实物等多重奖励,同步开启话题互动。点击链接参与,每周解锁数据库实战新场景。
|
11月前
|
缓存 NoSQL Linux
在CentOS 7系统中彻底移除MongoDB数据库的步骤
以上步骤完成后,MongoDB应该会从您的CentOS 7系统中被彻底移除。在执行上述操作前,请确保已经备份好所有重要数据以防丢失。这些步骤操作需要一些基本的Linux系统管理知识,若您对某一步骤不是非常清楚,请先进行必要的学习或咨询专业人士。在执行系统级操作时,推荐在实施前创建系统快照或备份,以便在出现问题时能够恢复到原先的状态。
1133 79
|
前端开发 数据库
会议室管理系统源码(含数据库脚本)
会议室管理系统源码(含数据库脚本)
244 0
|
SQL Oracle 关系型数据库
用 YashanDB Migration Platform,数据库迁移不再是“高风险动作”
数据库迁移一直是企业信息化中的难题,耗时长、风险高。YashanDB Migration Platform(YMP)提供一站式解决方案,涵盖评估、改写、迁移与校验全流程。其核心能力包括SQL自动适配、智能对象迁移、高性能数据通道及数据对比校验,显著降低人力成本与业务风险。适合从Oracle、MySQL等迁移到YashanDB的企业,以及需异构整合或国产化替代的集团、政府和国企项目。YMP不仅是工具,更是推动数据库国产化的关键平台。
|
9月前
|
安全 关系型数据库 数据管理
阿里云数据库:构建高性能与安全的数据管理系统
阿里云数据库提供RDS、PolarDB、Tair等核心产品,具备高可用、弹性扩展、安全合规及智能运维等技术优势,广泛应用于电商、游戏、金融等行业,助力企业高效管理数据,提升业务连续性与竞争力。
|
12月前
|
关系型数据库 MySQL 数据库
MySQL数据库上云迁移
本文介绍了将数据库迁移到RDS for Mysql的两种主要方法:停服迁移和不停服迁移。停服迁移适合可短暂中断服务的场景,通过mysqldump或DTS完成;不停服迁移适用于需保持业务连续性的场景,推荐使用DTS实现结构、全量及增量数据迁移。文中详细列出了每种方法的具体操作步骤,帮助企业根据需求选择合适的迁移方案。
371 1
MySQL数据库上云迁移