【发布时间】:2016-11-08 20:48:05
【问题描述】:
在我的项目中,我使用 spring-data-neo4j 4.2.0.M1 和 neo4j-ogm 2.0.4。最初这是使用嵌入式 neo4j 实例,但在调查此问题的过程中,我已使用 Bolt 协议迁移到专用的 neo4j 实例(虽然在同一台机器上运行)。
我在不断地插入数据,基本上是因为它对我的应用程序可用(所以我不能使用批量插入)。启动后,这工作正常,保存我的 NodeEntity 的实例大约需要 60 毫秒,这对我的用例来说非常好。然而,随着时间的推移,这会慢慢退化。 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 profiler(采样器模式!)我可以看到大部分时间似乎都花在neo4j-ogm的EntityGraphMapper上,特别是在
org.neo4j.ogm.context.EntityGraphMapper#haveRelationEndsChanged
正在保存的 NodeEntity 通常与其他节点有大约 40 个关系,其中大多数被建模为RelationshipEntity。在早期阶段,我已经注意到保存实体非常慢,因为也映射了太多相关(但未更改)的实体。从那时起,我在保存时使用深度 1。 导致节点实体被保存的连续操作使用 200 个实体的事务大小。
我还不相信,neo4j-ogm 实际上是放缓的原因,因为与良好的初始结果相比,我看不出有什么变化。 在这种情况下,我通常会怀疑内存泄漏/污染,但所有监控结果在我的应用程序中看起来都不错。对于 neo4j 服务器实例,除了 debug.log 之外,我真的不知道在哪里可以找到此类信息。
总而言之,我已经花了相当长的时间对此进行调查,但不知道还要看什么。有什么想法或建议吗?我很乐意提供更多信息。
编辑:根据@vince 的意见,我再次查看了内存分布,发现实际上 Neo4jSession 在让应用程序运行约 3 小时后增长了很多:
当时堆有 1.7 GB 大,其中 70% 引用了实时数据。其中,Neo4jSession 当前引用了大约 300mb(并保持活动状态)。这可能表明它已经变得太大了。 我怎么能在这里手动干预?
【问题讨论】:
-
您是为每个事务(200 个实体的批次)创建一个新会话,还是使用单个会话?
-
我正在使用相同的会话(我认为)。我没有任何手动处理会话,也使用默认范围。根据我从文档中了解到的情况,这对于长时间运行的操作应该有利于性能吗?在此期间,我不希望在我的工作线程之外有任何更新。
-
实体在会话中停留,直到它们被垃圾收集。如果您要加载数千个实体,
haveRelationEndsChanged可能会对性能产生一些影响,因此可能值得在每个事务之间执行session.clear()看看这是否有帮助。 -
@Vince:很好的建议,这似乎成功了!之前运行 3 小时的相同测试现在只需要 40 分钟,并且所有数据库插入的时间都是恒定的。由于现在这比请求进来的速度快,所以问题就解决了。我会尝试增加交易规模,因为我猜 200 太小了。请添加您的建议作为答案,我会接受。
标签: neo4j database-performance spring-data-neo4j-4 neo4j-ogm yourkit