分布式下带索引入库的性能问题

  • nebula 版本:v2.0
  • 部署方式(分布式 / 单机 / Docker / DBaaS):docker 分布式
  • 硬件信息
    • 磁盘( 必须为 SSD ,不支持 HDD)SSD
    • CPU、内存信息:40C 126G
  • 出问题的 Space 的创建方式:执行 describe space xxx;
  • 问题的具体描述
    你好,我用docker swarm在两台机器上部署了nebula,带索引进行入库速率测试。
    之前在单台机器上测试时遇到了很大的性能瓶颈,因此期望通过增加机器数量来加快入库速率,但是测试结果和单机时没有任何提升,这一点实在是无法理解,特请教下原因。

我的部署节点结构如下:
机器1:meta、storage、graph
机器2:storage、graph

schema:

CREATE TAG IF NOT EXISTS linux_process(pname string DEFAULT "", cmd string DEFAULT "", cmd_id string DEFAULT "",
        agent_ip string DEFAULT "", agent_id string DEFAULT "");
CREATE EDGE IF NOT EXISTS linux_process_create(unified_time int DEFAULT -1);

CREATE TAG INDEX IF NOT EXISTS  linux_process_index on linux_process(pname(100));
CREATE EDGE INDEX IF NOT EXISTS  linux_process_create_index on linux_process_create(unified_time);

host:

下面是我测试的一些双机和单机下的对比数据:
storaged cpu占比:
单机


双机

入库速率:
单机:https://discuss.nebula-graph.com.cn/t/topic/2266这篇帖子中有写
双机:初始入库速率2万多/s,后续不断衰减,最后降到2000/s。

请nebula的大佬给些建议,带索引插入性能实在下降的太厉害。
查了查以前的帖子https://discuss.nebula-graph.com.cn/t/topic/918/6,nebula的大佬说带索引能够达到10万/s,但是目前经过实际测试来看最多也只能达到2万多/s,而且不断衰减到2000/s. 这是我们的配置问题吗?

关于数据入库性能衰减严重的问题,并不是因为配置的问题,其根本原因是nebula的索引存储逻辑导致,这个性能衰减问题我们正在想办法解决,在解决这个问题之前,我有如下几个建议来提高导入性能:
1,根据实际硬件环境改变每批次导入的数据量
2,通过多个graphd并行导入,导入的客户端最好分布在不同的机器上
3,当性能衰减的很厉害时,不妨调用一个compact job,这个job执行完成之后,导入性能应该可以回升
4,如果是初始的数据导入,建议先不要创建索引,待数据导入完毕后,执行compact,然后再rebuild index,2.0 马上就可以支持一次rebuild 多个index了,PR已提交,很快就会merge

3 个赞

关于第二条,我在三台机器上分布式部署nebula,同时启动三个导入程序来带索引导入,在这三台上的导入速率的总和和单机测试时的导入速率大致相同,也就是通过水平扩展机器并没有带来性能增强,这一点很让人费解。
关于第三条,compact后性能虽然有一定回升,但是回升有限,达不到我们的性能要求。而且一直compact的话也job队列一直被compact占用,也无法执行其他job了。
我当前的配置是按照如下建议配置的:

  • 使用SSD代替HDD;

  • 带索引新写入前执行下compact;

  • 减少索引的数量,除了lookup语句需要索引,其他查询语句均不需要索引;

  • 入库前测试下磁盘的性能;

  • 使用批量导入时,使用较大的batch size;

  • partition数量设置为硬盘数量的五倍以上;

  • rocksdb的block cache设置为内存的三分之一。block cache越大,读索引时也就越快;

这个问题的根本原因是因为在导入数据的时候,如果有索引,那么就需要去查询是否存在老的数据,如果存在的话,需要把原有的索引删除。

所以,能不能详细介绍一下你们的使用场景,包括是否是初次导入,还是后续的批量导入?导入的数据都是新数据还是会覆盖老数据

1 个赞

我们的使用场景是24小时不间断的从kafka读取json数据并入库,导入的数据都是新数据,没有覆盖老数据的情况。入库速率衰减是刚开启入库程序就开始不断衰减。
关于索引有一个建议,索引的build操作可以设计成像手动compact一样,手动触发,每次手动构建索引都是对新入库的增量数据构建索引(已经构建完索引的数据则无需再次构建),而不是在数据导入时必须实时构建索引,这样在带索引入库的性能问题没有解决时,我们也可以采用定时build索引的方式,保证数据导入在一个较高的速率。

增量构建索引 这个是可以 前提是对索引和数据的一致性需要放宽 因为索引查出来可能是错的 或者是漏了。速度和一致性有trade off

你好,用spark exchange以sst方式导入的话,相较通过NGQL语句导入会有明显的速率提升,但是exchange的配置文件只能实现属性的一对一映射,无法在字段上施加一些定制化的业务逻辑。而我们从kafka读出的数据还需要一些额外处理才能入库,所以可能还需要再单独维护一套kafka集群用来对接经过业务处理的json数据和exchange,这样维护成本又上升了。
我想咨询一下,如果我们单独实现exchang生成sst的逻辑,然后把这套逻辑内置在我们原先的导入程序中,直接让我们的导入程序生成sst,不再使用exchange,这样自己实现的成本会不会很高呢,我们的导入程序是go语言实现的。

没有完全理解。听起来是使用exchange不能直接满足你们的需求,如果想使用sst来导入又相对可控,这个sst文件就得自己来生成,据我所知好像用go应该是做不了。现在是用的2.0版本的话,java client那边是有一个能生成sst工具的,还有就是rocksdb的c。

得看go有没有生成rocksdb sst的接口了。

exchange的配置文件只能定义kafka中的数据和图数据库的数据在tag和edge属性上的一对一关系,但是我们这边对从kafka读取出的数据还要做一些业务转换才能入库,所以只依赖exchange是做不到这些业务上的处理的。
如果我们自己生产sst,然后把sst手动拷贝到nebula storage的data目录的download目录下再执行ingest,这个方案在理论上是可行的吗

可行,有从hdfs download的命令。

如果全部是新数据,我们有一个方案可以几乎达到没有index的导入速率,但是没有合进主干。有兴趣的话,我们可以私聊。

太感谢了,带索引入库的问题困扰我们很久了,可以私聊一下,我直接在微信上联系nebula客服可以吗。

你好,我想问下,如果是集群多节点部署的nebula,使用donwload hdfs命令去hdfs下载下来sst文件,这些下载下来的sst文件是数量均匀分布在所有的storaged节点的download目录下,还是全部都保存在某一个storaged节点的download目录下呢?
如果是均匀分布的,那如果我手动把sst都放在一个storage节点上进行ingest可行吗,还是说会有其他问题?

建议 直接在exchange 上进行修改

这个是将该 storage 节点所持有的 partition 的SST 文件下载到相应节点上

如果将不属于该storage节点所持有的partition的sst文件放在了该storaged节点下,执行ingest的话,该storage节点会将这些不属于它的sst文件内数据分发到其他storaged节点么?
之所以想自己实现是因为不想再引入spark和hadoop,减轻运维和存储压力。

不会 这相当于违背了storage这边的分片规则

1 个赞

问题是 没有Spark 你的SST 哪儿来呢? 手动生成嘛?

是的,我们想自己实现一套sst生成模块,跟我们的业务代码结合起来,目前exchange的配置文件不够灵活,只能实现源数据到nebula schema数据的一对一映射,我们对源数据还有业务处理在里面。