乐趣区

关于数据库:数据库重构之路以-OrientDB-到-NebulaGraph-为例

“本文由社区用户 @阿七从第一视角讲述其团队重构图数据库的过程,首发于阿七公众号「浅谈架构」”

原文出处:https://mp.weixin.qq.com/s/WIJNq-nuuAGtMjYo5rPLyg

一、写在后面

读过我公众号文章的同学都晓得,我做过很屡次重构,能够说是“ 重构钉子户 ”,然而这次,重构图数据库 OrientDB 为 NebulaGraph(https://www.nebula-graph.com.cn/),能够说是我做过最艰巨的一次重构。

那这篇文章就来聊聊,图数据库重构之路。

二、难点在哪里

  1. 历史包袱重 ,原来应用 OrientDB 零碎是 2016 年开始开发的,逻辑很简单,历史背景齐全不分明。
  2. 业务不理解 ,咱们是长期接的大数据需要,之前没有参加过这块业务,齐全不理解。
  3. 技术栈不理解 ,图数据库是第一次接触(团队中也没有人理解),OrientDB 和 NebulaGraph 之前都没有接触过,原来老零碎大部分代码是 Scala 语言写的,零碎中应用的 HBase、Spark、Kafka,对于咱们也比拟生疏。
  4. 工夫紧迫

总结来说: 业务不理解,技术栈不相熟

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

三、技术计划

上面介绍一下本次重构技术计划

1、迁徙背景

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

老零碎是用应用技术栈无奈反对弹性伸缩,监控报警设施也不够欠缺。

具体的应用痛点后续我将会写一篇文章具体讲述下,本篇就不具体开展了。

2、调研事项

注:既然业务都不相熟,那咱们都调研了哪些货色呢?

  1. 对外接口梳理 :梳理零碎所有对外接口,包含接口名、接口用处、申请量 QPS、均匀耗时,调用方(服务和 IP);
  2. 老系统核心流程梳理 :输入老零碎整顿架构图,重要的接口(大略 10 个)输入流程图;
  3. 环境梳理 :波及到的须要革新的我的项目有哪些,利用部署、MySQL、Redis、HBase 集群 IP,及目前线上部署分支整顿;
  4. 触发场景 :接口都是如何触发的,从业务应用场景登程,每个接口至多一个场景笼罩到,不便前期性能验证;
  5. 革新计划 :可行性剖析,针对每一个接口,如何革新(OrientDB 语句改为 NebulaGraph 查问语句),入图(写流程)如何革新;
  6. 新零碎设计方案 : 输入整顿架构图,外围流程图。

3、我的项目指标

​实现图数据库数据源 OrientDB 革新为 NebulaGraph,重构老零碎对立技术栈为 Java,反对服务水平扩大。

4、整体计划

咱们采纳了比拟激进的计划:

  1. 从调用接口入口登程,间接重写底层老零碎,影响面可控;
  2. 一劳永逸,不便前期保护;
  3. 对立 Java 技术栈、接入公司对立服务框架,更利于监控及保护;
  4. 根底图数据库利用边界清晰,后续下层利用接入图数据库更简略。

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

5、灰度计划

灰度计划

  • 写申请:采纳同步双写
  • 读申请:按流量从小到大陆续迁徙、平滑过渡

灰度打算

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

注:

  1. 配置核心开关管制,有问题随时切换,秒级复原。
  2. 读接口脱漏无影响, 只有改到的才会影响。
  3. 应用参数 hash 值作为 key,确保同一参数屡次申请后果统一、满足 abs(key) % 1000 < X (0< X < 1000,X 为动静配置) 即为命中灰度。

题外话: 其实重构,最重要的就是灰度计划 ,这个我在之前文章《浅谈这些年做过的千万级零碎重构我的项目》也提到过。本次灰度方案设计比较完善,大家重点看阶段一、在灰度放量之前,咱们用线上实在的流量去异步做数据比照,比照齐全通过之后,再放量,本次比照阶段比预期长了很多(实际上用了 2 周工夫,发现了很多问题)。

6、数据比照计划

未命中灰度

未命中灰度流程如下:

先调用老零碎,再依据是否命中采样(采样比例配置 0% ~ 100%),命中采样会发送 MQ,再在新零碎生产 MQ,申请新零碎接口,于老零碎接口返回数据进行 JSON 比照。比照不统一,发送企业微信告诉,实时感知数据不统一,发现并解决问题。

反之亦然!!

7、数据迁徙计划

  1. 全量(历史数据):写脚本全量迁徙,上线期间产生不统一从 MQ 生产近 3 天数据
  2. 增量:同步双写(写的接口很少,写申请 QPS 不高)

8、革新案例 – 以子图查问为例

革新前:

@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;
    }

革新后:

定义灰度模块接口

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);
}

接口革新如下,kgpCoreService 申请到 kgp-core 新服务,接口业务逻辑和 orion-x 保持一致、底层图数据库改为查问 NebulaGraph:

@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 = kgpCoreService.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 人

次要事项及耗时如下:

10、所需资源

略,这里不开展讲述。

四、重构收益

通过团队 2 个月奋斗,目前已实现灰度阶段,收益如下

  1. NebulaGraph 自身反对分布式扩大,新零碎服务反对弹性伸缩,整体反对性能程度扩大;
  2. 从压测后果看,接口性能晋升很显著,可撑持申请远超预期;
  3. 接入公司对立监控、告警,更利于前期保护。

五、总结

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


谢谢你读完本文 (///▽///)

如果你想尝鲜图数据库 NebulaGraph,记得去 GitHub 下载、应用、(^з^)-☆ star 它 -> GitHub;和其余的 NebulaGraph 用户一起交换图数据库技术和利用技能,留下「你的名片」一起游玩呀~

2023 年 NebulaGraph 技术社区年度征文活动正在进行中,来这里支付华为 Meta 60 Pro、Switch 游戏机、小米扫地机器人等等礼品哟~ 流动链接:https://discuss.nebula-graph.com.cn/t/topic/13970

退出移动版