apache / incubator-hugegraph

A graph database that supports more than 100+ billion data, high performance and scalability (Include OLTP Engine & REST-API & Backends)
https://hugegraph.apache.org
Apache License 2.0
2.6k stars 513 forks source link

关于写图效率过低问题 #883

Closed CPJ-data closed 2 years ago

CPJ-data commented 4 years ago

各位大佬好,烦请各位大佬解答一下 正式服务:普通盘,24核128G 测试服务:虚拟SSD,16核16G 本机:普通盘1T,运行内存16G 本机:SSD盘256G,运行内存16G 本机测试跑本地代码测试十分钟,提供一下数据参考 1、正式服务:普通盘,24核128G 16个线程进行写图,跑1天17小时写入数据84W不到。 查看后台日志,在查询过程中耗时大概是27000~28000ms之间 2、测试服务:虚拟SSD,16核16G 16个线程进行写图,跑1天写入数据66W不到。 查看后台日志,在查询过程中耗时大概是6000~8000ms之间 3、本机:普通盘1T,运行内存16G 10个线程操作写图,十分钟数据4.2W不到,前面两分钟大概写入速度每分钟1W左右,随着数据量增加,后五分钟写入大概0.5W 4、本机:SSD盘256G,运行内存16G 10个线程操作写图,十分钟数据4.6W不到,前面3分钟大概写入速度每分钟1W左右,前五分钟大概是每分钟0.8W左右,随着数据量增加,后五分钟写入大概0.5W 本机测试在后台没得日志显示,根据每分钟查看g.E().count()进行统计的,随着数据量增加g.E().count()查询时间越来越慢。 注:代码中查询点边的语句,使用的是gremlin语法操作。 注:后端存储Cassandra,集群部署 根据这四种情况分析 1、主要的瓶颈是在查询这块耗时过长,尤其是在正式查询一次耗时28S 2、硬件问题--普通盘对于图谱的操作性能影响较大 3、使用查询语法是否有问题,导致查询时间过长 如:gremlinManager.gremlin("g.V().has(" + "\"" + eid + "\"," + "\"" + eid + "\"" + ")").execute()进行查询操作。

烦请各位大佬帮忙解答一下,在软件方面还存在哪些可以优化的情况,感谢

javeme commented 4 years ago

10个线程操作写图,十分钟数据4.2W不到,前面两分钟大概写入速度每分钟1W左右,随着数据量增加,后五分钟写入大概0.5W

@CPJ-data 这个和正常速度差太多了,从上面的描述不太好定位原因,为了方便分析可以提供下:Cassandra集群的具体软硬件情况、测试程序是和查询语句等

CPJ-data commented 4 years ago

@javeme Cassandra:版本apache-cassandra-3.11.0 硬件: E5-2643 V4 3.4G2/16G8/H730 1G/1.8T 10K RPM SAS8/750W2/10GE网卡
测试程序代码:

            Entity startEntity = kgRecord.startEntity;
            Entity endEntity = kgRecord.endEntity;
            HugeClient hugeClient = getG();
            GremlinManager gremlinManager = hugeClient.gremlin();
            Vertex startVertex = null;
            String startEid =
                HugeGraphData(gremlinManager.gremlin("g.V().hasLabel(" + "\"" + startEntity.getLabel().label + "\"" + ").has(" + "\"" + PropertyKey.eid + "\"" + "," + "\"" + startEntity.getEid() + "\"" + ")").execute());
            System.out.println("输出hugeGraph的EID值===" + startEid);
            boolean isStartVAdd = false;
            boolean isEndVAdd = false;
                    if (startEid != null){
                        //更新
                        startVertex = updateVertex(startEntity, startEntity.getEid(), gremlinManager);
                        return Tuple3.of(true, false, false);
                    }else {
                        //添加点
                        startVertex = insertVertex(hugeClient, startEntity);
                        return Tuple3.of(true, false, false);
                    }
            }             

HugeGraphData这是一个数据转换方法。
查询语句:gremlinManager.gremlin("g.V().hasLabel(" + "\"" + startEntity.getLabel().label + "\"" + ").has(" + "\"" + PropertyKey.eid + "\"" + "," + "\"" + startEntity.getEid() + "\"" + ")").execute()都是已这种语句进行查询,之前也有提过一个问题,当不断进性查询操作时,hugegraph后台日志报错:提示请求失败。 对于程序这块的代码,不能够提供太多,读取kafka的数据量400W样子,服务器性能上面已经说过 不知道提供这些信息是否方便定位问题,感谢感谢

CPJ-data commented 4 years ago

@javeme 不断请求hugegraph进行数据查询,请求失败 #879

javeme commented 4 years ago

@CPJ-data 看起来大概率是测试程序问题,核心的点在于写入的时候还伴随着大量的读操作,如果是机械盘的话,性能肯定会很低。建议:

  1. 去掉读操作
  2. 或者使用SSD盘可以有所缓解,并结合使用update strategy更新属性 #744

另外,Cassandra软硬件信息主要包括:集群节点数,各节点CPU、内存、磁盘、网卡。

CPJ-data commented 4 years ago

@javeme Cassandra 集群:3个 R730 2U dell服务器 E5-2643 V4 3.4G2 cpu 内存:整个磁盘空间 cas启动内存是 -Xmx8192M 1.8T 10K RPM SAS8 SAS盘 10GE 万兆网卡 去掉读操作 1、针对于去掉读操作,这个针对于整个流程来说是不现实的,在整个400多万数据中,为了避免写入重复的点,在写入前进行判断是否已包含该点。 ①之前有测试过janus写图,也是同样的读写,单线程操作,测试一分钟1000左右(部署在容器中),正式2000左右(部署在容器中) ②hugegraph16个线程操作,测试每分钟458左右(虚拟固态SSD),正式340左右(普通盘) ③neo4j的同样的流程,16个线程跑10分钟64W数据 或者使用SSD盘可以有所缓解,并结合使用update strategy更新属性 2、使用SSD盘,暂时无法实现,在本机测试机械盘和SSD的盘进行少量数据写入,数据量超过3W后,也是写入效率特别慢。

是否有好的方法可以解决这个读写操作时,读这块特别耗时问题。

879 这个不断的进行读操作,导致后续hugegraph服务端响应不过来导致报错,这块只进行读hugegraph的数据,存储到数据库中,完全没有写操作。

对于读这块有比较大的瓶颈,需要什么操作才能解决这个问题。硬件升级固态SSD,本机测试数据的写入也没有特别大的提升,而且暂时无法实现硬件升级SSD盘。

CPJ-data commented 4 years ago

@javeme 刚在本机针对于只写进行测试 本机:普通盘1T,运行内存16G——11分钟写入153149 如果进行读写:10分钟写入不到4.2W 本机:SSD盘256G,运行内存16G_11分钟写入150011 如果进行读写:10分钟写入不到4.6W

imbajin commented 4 years ago

唔... 看的有点费眼, 建议稍微空行或者使用一下md语法优化下排版 而且描述的例子有点太杂了, 信息需要整理一下..

我先简单说下我看到的两个问题定位思路, 仅供参考:

  1. 写入慢
    • 是用loader写的么, 正常的覆盖写速度至少应该是万级别的 (你的速度太低)
    • 如果是loader写的但这么慢, 可以用Arthas看看loader慢在哪了
    • 如果loader发的很快但是响应很慢, 你可以再Arthas监控一下server发给后端的速度
    • 可以尝试先不用Cassandra, 用RocksDB单机测下导入速度 (控制变量, 缩小问题范围)
  2. 随机读/更新慢
    • 先不用急着换SSD测试, 先监测一下你更新时的磁盘IOPS使用, 看看到底是不是IOPS瓶颈了
    • 如果磁盘IOPS并不高, 那说明当前还不是这个问题, 先一个个确认排查
    • 如果IOPS的确满了, 那也不应该速度这么慢, 更应该用Arthas定位一下到底慢在哪了

补充: 可以打一下loader和server的火焰图, 看看大家在忙啥.

总之先尽量从简单的来排查, 如果写入速度就特别慢, 那就不用去测更新的问题了, 一个个解决

javeme commented 4 years ago

@CPJ-data 正如imbajin所说,正常情况下hg写性能至少是每秒万级别的。 看了后面给出的信息,应该是Cassandra的分配内存太小导致的-Xmx8192M,建议分配64G以上。

另外,针对如下疑问分别解答:

①之前有测试过janus写图,也是同样的读写,单线程操作,测试一分钟1000左右(部署在容器中),正式2000左右(部署在容器中) ②hugegraph16个线程操作,测试每分钟458左右(虚拟固态SSD),正式340左右(普通盘)

后端存储环境是否相同?如果后端存储不一样的话,需要统一环境进行测试。

③neo4j的同样的流程,16个线程跑10分钟64W数据

neo4j是单机测的吧?如果需要将hugegraph与neo4j对比的话,可以使用单机版rocksdb后端(单机rocksdb性能远高于3节点cassandra集群),我们的benchmark测试中,性能是优于neo4j的。

CPJ-data commented 4 years ago

@imbajin @javeme 感谢大佬的回复

1.针对于写操作 ①:是通过client连接server进行写入操作,而之前通过loader快速导入数据,效率还是比较快。 ②:代码逻辑只进行写操作,一分钟大概写入8500条左右的样子,效率基本可以满足。 ③:Arthas这块的知识暂时还没有使用过,没有通过这个进行操作。后续会进行这块知识点的学习。

2.针对于读操作 ①:读这块是导致效率变慢的主要原因,现使用gremlin的语法进行查询操作,是否有更优化的语法,之前看到有介绍REST—API,但是没有找到具体API的介绍。 ②:现在想如何通过程序的优化解决这个读耗时过长问题。

3:janus和hugegraph的后端存储都是一样的,都是Cassandra。 4:neo4j是单机测试。

磁盘测试的读写能力 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn scd0 0.00 0.11 0.00 1028 0 sda 1.88 48.63 12.05 437204 108334 dm-0 1.73 45.38 11.82 407993 106245 dm-1 0.01 0.25 0.00 2228 0

Cassandra的内存已经调到32G,调的是/bin/cassandra-env.sh文件中的内存

针对于这个读写优化已经卡住了很长时间了,麻烦各位大佬答复了

javeme commented 4 years ago

@CPJ-data gremlin语句是什么样的呢?一条查询语句返回结果有多少? rest api 文档:https://hugegraph.github.io/hugegraph-doc/clients/restful-api/traverser.html

CPJ-data commented 4 years ago

@javeme gremlin查询返回的结果一般都是一条结果:如——gremlinManager.gremlin("g.V().has(" + """ + eid + ""," + """ + eid + """ + ")").execute()查询操作

看了一下rest api文档和在程序中使用定义是差不多,具体的细节还去好好研究一下

早上过来看了一下昨天跑只写流程已写数据800多万了(17h),按照这速度一天应该能写一千万的数据量。查询这块这么耗时不知是否有个具体操作方案可以解决。感谢大佬

CPJ-data commented 4 years ago

@javeme 大佬你好 针对于这个查询耗时过长的问题,有几个疑问 1、如果是硬件问题,那么什么样的硬件才能达到合格的标准。(暂时对于提升硬件标准不现实) 2、不知贵司是否针对于写图这块功能,边写入数据边查询的效率测试,如有是否方便提供一些资料参考,查找的资料信息都比较少。 3、针对于查询语法是否还有什么可以优化的空间,在studio上进行查询,如果数据量比较多查询单个点,第一次进行查询的时候耗时较长(进行过亿级别数据的查询)。 4、gremlin语法是否针对于该图不是最优的查询语法。

javeme commented 4 years ago

@CPJ-data 在机械盘上进行大量read-updae-write操作,会导致性能低下,是所有数据库一个比较普遍的问题,和查询语法没有关系的。核心建议:

RocksDB单机版性能(48CPUs 128G内存 HDD盘)

https://hugegraph.github.io/hugegraph-doc/performance/hugegraph-api-0.5.6-RocksDB.html

RocksDB单机批量写性能

RocksDB单机单条写性能

RocksDB单机随机读性能

Cassandra集群版性能(15节点,48CPUs 128G内存 HDD盘)

https://hugegraph.github.io/hugegraph-doc/performance/hugegraph-api-0.5.6-Cassandra.html

Cassandra集群批量写性能

Cassandra集群单条写性能

Cassandra集群随机读性能

CPJ-data commented 4 years ago

@javeme 感谢答复

在机械盘上进行大量read-updae-write操作,会导致性能低下,是所有数据库一个比较普遍的问题,和查询语法没有关系的。核心建议:

去掉读操作,将更新写换为覆盖写 或者,使用SSD盘进行更新操作

1、程序中的更新操作,一直都是覆写。

2、去掉读的问题,怎么保证该点的唯一性。 数据中存在如:爷——子——孙这样的关系的公司,存在一个子公司存在控股多家孙公司的情况,所以进行查询读取数据操作保证不重复写入已存在的点。

3、如下是hugegraph的server端查询一次显示的耗时时间:7278ms

2020-03-11 17:56:05 99710635 [gremlin-server-exec-10] [WARN ] org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine [] - Script compilation g.V().hasLabel("company").has("eid", "e82ab3005d3f7a7d165e264251439369") took 7278ms

①:针对于eid的查询,在定义schema的时候定义了二级索引。

②:一般这种单点的查询耗时应该是在毫秒级别,而不应该会到秒级别了。

③:想到将数据点的封装到map中,但如果服务重启,map重新实例数据就会清空,而之前封装的数据也毫无意义,redis也是同样。

javeme commented 4 years ago

@CPJ-data 看起来还有一些理解不一致的地方,先明确一下我前面提到的更新写和覆盖写:

覆盖写可以参考一下这个issue中的实现思路:https://github.com/hugegraph/hugegraph/issues/890#issuecomment-597571021

如下是hugegraph的server端查询一次显示的耗时时间:7278ms

这个查询耗时7s当然是不正常的,正常是在毫秒级。有2个可能的原因:

CPJ-data commented 4 years ago

@javeme 大佬你好

另一个可能是gremlin引擎编译缓慢。针对这种情况,可以尝试使用rest-api 2.1.5 获取符合条件的顶点进行请求,如果这时速度正常则证明是gremlin引擎问题。期待你的验证结果。

查看了文档和代码,这块是使用hugegraph-API中的hugeGraph.traversal().V()方法进行查询,现在有点地方没有搞懂 API中的Graph方法:

public static HugeGraph graph(GraphManager manager, String graph) {
    HugeGraph g = manager.graph(graph);
    if (g == null) {
        throw new NotFoundException(String.format(
                  "Graph '%s' does not exist",  graph));
    }
    return g;
}

在程序中:

HugeConfig hugeConfig = new HugeConfig(configuration); GraphManager graphManager = new GraphManager(); HugeGraph hugeGraph = graphManager.graph("graph");

①:定义String类型的graph是不是数据库中存储数据的库名。

②:这块的代码需要怎么进行定义,才能正确使用hugegraph-api中hugegraph。

③:麻烦大佬帮忙解答一下,如果方便的话能否贴一下代码参考一下。非常感谢

Linary commented 4 years ago

@CPJ-data 你好

  1. 确切的说:graph是图的名字(在rest-server.properties中配置),不一定是数据库中的库名(在hugegraph.properties中配置),这两者是可以不一样的;
  2. 这一块的代码是server起来的时候对图做一些配置和管理的,用户不用去管这儿。
  3. 使用RESTful API获取符合条件的顶点示例如下

请求

GET http://localhost:8080/graphs/hugegraph/graph/vertices?label=person&properties={"age":29}&limit=1

其中

响应

{
    "vertices": [
        {
            "id": "1:marko",
            "label": "person",
            "type": "vertex",
            "properties": {
                "city": [
                    {
                        "id": "1:marko>city",
                        "value": "Beijing"
                    }
                ],
                "name": [
                    {
                        "id": "1:marko>name",
                        "value": "marko"
                    }
                ],
                "age": [
                    {
                        "id": "1:marko>age",
                        "value": 29
                    }
                ]
            }
        }
    ]
}
Linary commented 4 years ago

@CPJ-data 上面的demo用HugeClient写的话大概是这样。

Map<String, Object> properties = ImmutableMap.of("age", 29);
List<Vertex> vertices = client.graph().listVertices("person", properties);
CPJ-data commented 4 years ago

@Linary 你好 想使用hugeGraph.traversal().V() 这种方法,有具体的API或者文档,代码可以参考没?

tangxin1121 commented 3 years ago

各位大佬好,烦请各位大佬解答一下 正式服务:普通盘,24核128G 测试服务:虚拟SSD,16核16G 本机:普通盘1T,运行内存16G 本机:SSD盘256G,运行内存16G 本机测试跑本地代码测试十分钟,提供一下数据参考 1、正式服务:普通盘,24核128G 16个线程进行写图,跑1天17小时写入数据84W不到。 查看后台日志,在查询过程中耗时大概是27000~28000ms之间 2、测试服务:虚拟SSD,16核16G 16个线程进行写图,跑1天写入数据66W不到。 查看后台日志,在查询过程中耗时大概是6000~8000ms之间 3、本机:普通盘1T,运行内存16G 10个线程操作写图,十分钟数据4.2W不到,前面两分钟大概写入速度每分钟1W左右,随着数据量增加,后五分钟写入大概0.5W 4、本机:SSD盘256G,运行内存16G 10个线程操作写图,十分钟数据4.6W不到,前面3分钟大概写入速度每分钟1W左右,前五分钟大概是每分钟0.8W左右,随着数据量增加,后五分钟写入大概0.5W 本机测试在后台没得日志显示,根据每分钟查看g.E().count()进行统计的,随着数据量增加g.E().count()查询时间越来越慢。 注:代码中查询点边的语句,使用的是gremlin语法操作。 注:后端存储Cassandra,集群部署 根据这四种情况分析 1、主要的瓶颈是在查询这块耗时过长,尤其是在正式查询一次耗时28S 2、硬件问题--普通盘对于图谱的操作性能影响较大 3、使用查询语法是否有问题,导致查询时间过长 如:gremlinManager.gremlin("g.V().has(" + """ + eid + ""," + """ + eid + """ + ")").execute()进行查询操作。

烦请各位大佬帮忙解答一下,在软件方面还存在哪些可以优化的情况,感谢

您好! 我在我的笔记本上测试时,写入顶点速度很快,但是写入边的时候需要先有顶点的ID,不管是先查询顶点再add边,还是先构建顶点在add 边,效率都很低,目前我使用的方法是在批量写入数据之前先查询该顶点标签的ID,后续写入时不再查询顶点ID,使用拼接ID的方式创建顶点、add边,效率提升五到十倍。

github-actions[bot] commented 2 years ago

Due to the lack of activity, the current issue is marked as stale and will be closed after 20 days, any update will remove the stale label