1

在我的项目中,我使用了spring-data-neo4j 4.2.0.M1和neo4j-ogm 2.0.4。最初,这是使用嵌入式neo4j实例,但在调查这个问题的过程中,我已经使用Bolt协议迁移到专用的neo4j实例(尽管在同一台计算机上运行)。Neo4j-ogm:减少写入/映射性能

我不断地插入数据,基本上,因为它变得可用于我的应用程序(所以我不能使用批量插入)。启动后,这工作正常,并保存我的NodeEntity实例需要〜60ms,这对我的使用情况来说非常好。然而,随着时间的推移,这会逐渐降低10-20分钟后,每次保存速度减慢到约2秒,这已经不再那么好了。时间似乎在这里达到顶峰,并没有减少太多。

最初我认为这是由嵌入式实例太小造成的,因为我看到了有关由neo4j报告的GC暂停的重复消息。然后,我已经迁移到一个更大的专用实例,并且这些GC警告不再显示。虽然降解仍然发生。

存储大小如Neo4j的报道:

Array Store 8.00 KiB 
Logical Log 151.36 MiB 
Node Store 40.14 MiB 
Property Store 1.83 GiB 
Relationship Store 742.63 MiB 
String Store> Size 120.87 MiB 
Total Store Size 4.55 GiB 

的实例提供配置如下:(!取样模式)

dbms.memory.pagecache.size=5g 
dbms.memory.heap.initial_size=4g 
dbms.memory.heap.max_size=4g 
dbms.jvm.additional=-XX:+UseG1GC 

使用YourKit探查我可以看到,大部分的时间似乎由Neo4j的,OGM的EntityGraphMapper在

org.neo4j.ogm.context.EntityGraphMapper#haveRelationEndsChanged 

度过的,特别是210

正在保存的NodeEntity通常与其他节点具有约40个关系,其中大多数关系建模为RelationshipEntity。在较早的阶段,我已经注意到保存实体的速度很慢,因为也有太多相关的实体(但没有变化)。从那时起,我在保存时使用的深度为1。 导致NodeEntitites被保存的连续操作使用200个实体的事务大小。

我还不确定,neo4j-ogm实际上是放缓的原因,因为我没有看到与良好的初始结果相比有什么变化。 在这种情况下,我通常会怀疑内存泄漏/污染,但是在我的应用程序中,所有监视结果都非常好。对于neo4j服务器实例,除了debug.log之外,我不知道在哪里查找这些信息。

总而言之,我已经花了相当一段时间调查这一点,不知道还有什么要看。任何想法或建议?我很高兴提供更多信息。

编辑:Follwing @文斯的投入,我已经再看看内存分配和发现,其实Neo4jSession已经让应用程序运行于〜3小时后成长颇多:

neo4j-ogm-memory

那时堆是1,7 GB大,其中70%参考了实时数据。除此之外,Neo4jSession目前引用了大约300MB(并保持活跃)。这可能表明它已经变得太大了。 我该如何手动干预?

+0

您是否为每个交易(一批200个实体)或使用单个会话创建新会话? – Vince

+0

我正在使用同一个会话(我认为)。我没有任何手动处理会话,也使用默认范围。从我从文档中了解的情况来看,对于长时间运行的操作,这应该是有益的性能表现?在此期间,我不希望在我的工作线程以外有任何更新。 – geld0r

+2

实体在会话中继续存在,直到他们收集垃圾。如果您加载了数千个实体,那么在'haveRelationEndsChanged'中可能会有一些性能影响,所以在每个事务之间执行'session.clear()'可能会有帮助。 – Vince

回答

1

实体一直呆在会话中,直到它们被垃圾收集。如果您加载的数千个实体可能会对性能产生一定的影响,因此在每次交易之间可能需要执行session.clear(),并查看是否有帮助

1

前段时间我们有几乎相同的情况,当时我们需要将大量的数据存储到neo4j。我们分析了不同的方法如何处理。所以我们找到了一些解决方案来加速向neo4j插入数据。

  1. 使用本地neo4j java驱动程序而不是spring-data。首先,它是异步API,并且如果select的数据可用性并不重要,那么它可以提供帮助。

  2. 使用事务插入多个记录(例如每个事务1000个插入)。它会加速插入,因为在任何事务提交之后,neo4j尝试使用lucene重新计算索引并且需要时间。在你的情况下(使用spring-data),任何插入都在单独的事务中执行。

+0

我真的很想避免为这个不同的导入任务编写手动查询。 Spring-data-neo4j/neo4j-ogm允许简化这一点。尽管类似的情况下,更新要处理的更类似,但我会记住这一建议。 – geld0r

2

希望现在为时尚晚,以解决此问题。

我最近在一个Set中保存一个具有〜900个关系的节点时可能会遇到同样的情况,并且可能会从〜5秒到500ms执行一次。我刚开始使用neo4j-ogm 2.1.3,并刚刚迁移到3.0.0。尽管3.0.0速度更快,但两个版本的性能增益相似。

下面是一些伪代码(我不能共享,现在真正的代码):

@NodeEntity(label = "MyNode") 
public class MyNode { 
    @GraphId 
    private Long id; 

    @Index(unique = true, primary = true) 
    private String myUniqueValue; 

    private String value; 

    @Relationship(type = "CONNECTS_TO") 
    private Set<MyRelationship> relationships; 
    // constructors, getters, setters 
} 

@Relationship(type = "CONNECTS_TO") 
public class MyRelationship { 

    @GraphId 
    private Long id; 

    @StartNode 
    private MyNode parent; 

    @EndNode 
    private MyNode child; 
    // constructors, getters, setters 
} 

注意MyNode有一个索引/独特的领域,我必须在价值完全控制。 neo4j-ogm将使用它来确定它是否应该执行CREATEMERGE声明。在我的用例中,如果节点已经存在,我希望合并发生。

另一方面,关系创建依赖于节点ID(@GraphId字段)。下面是生成的语句的一个小片段,创建它:

UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId...

在低速模式下,Neo4j的,OGM将核实关系或其中的节点是否已保存的照顾和将检索的ID创建节点所必需的。这是您在YourKit中捕获的操作。

执行缓慢的一个例子:

void slowMode() { 
    MyNode parent = new MyNode("indexed-and-unique", "some value"); 
    for (int j = 0; j < 900; j++) { 
     MyNode child = new MyNode("indexed-and-unique" + j, "child value" + j); 
     parent.addRelationship(new MyRelationship(parent, child)); 
    } 
    session.save(parent); // save everything. slow. 
} 

我找到了解决的办法是打破这些业务分为三个部分:

  • 保存父节点只

  • 保存子节点

  • 保存rela tionships

这是更快:

void fastMode() { 
    MyNode parent = new MyNode("indexed-and-unique", "some value"); 
    for (int j = 0; j < 900; j++) { 
     MyNode child = new MyNode("indexed-and-unique" + j, "child value" + j); 
     parent.addRelationship(new MyRelationship(parent, child)); 
    } 
    session.save(parent, 0); // save only the parent 
    session.save(getAllChildsFrom(parent), 0); // save all the 900 childs 
    // at this point, all instances of MyNode will contain an "id". time to save the relationships! 
    session.save(parent); 
} 

有一点要注意:Neo4j的-OGM 2.1。3在保存节点集合(session.save(getAllChildsFrom(parent), 0))时没有执行单个批处理语句,该节点仍然很健谈,速度也很慢,但并没有像以前那么慢。 3.0.0版解决了这个问题。

希望它有帮助!