知识库

预热缓存以提高冷启动性能

注意: 对于 3.5.x 及更高版本,以下详细信息不再适用,因为 Neo4j 将始终记录页面缓存中的内容,并且在 Neo4j 重新启动后,页面缓存将自动使用之前在页面缓存中的数据进行预热。在 3.5.x 及更高版本中,logs\debug.log 将报告类似于

2020-12-14 21:00:08.486+0000 INFO [o.n.k.i.p.PageCacheWarmer] Page cache warmup started.
2020-12-14 21:00:08.659+0000 INFO [o.n.k.i.p.PageCacheWarmer] Page cache warmup completed. 441 pages loaded. Duration: 173ms.

注意: 对于 Neo4j 2.3+,不再有对象缓存,因此这会预热将 Neo4j 存储文件映射到内存的页面缓存。

您可能会发现某些查询在第二次运行时运行得快得多。这是因为在冷启动时,服务器节点还没有任何缓存,并且需要访问磁盘以获取所有记录。一旦某些/所有记录被缓存,您将看到性能大幅提升。

一种广泛采用的技术是“预热缓存”。在最基本的层面上,我们运行一个查询,该查询会访问图中的每个节点和关系。假设数据存储可以放入内存,这将缓存整个图。否则,它将尽可能多地缓存。试试看,看看它对您是否有帮助!

Cypher (服务器,Shell)
MATCH (n)
OPTIONAL MATCH (n)-[r]->()
RETURN count(n.prop) + count(r.prop);

在上面的示例中,对 count(n.prop) + count(r.prop) 的引用用于强制优化器搜索具有名为 'prop' 的属性的节点/关系。用 count(*) 替换它是不够的,因为它不会加载所有节点和关系属性。

嵌入 (Java)
@GET @Path("/warmup")
public String warmUp(@Context GraphDatabaseService db) {
  try ( Transaction tx = db.beginTx()) {
    for ( Node n : GlobalGraphOperations.at(db).getAllNodes()) {
      n.getPropertyKeys();
      for ( Relationship relationship : n.getRelationships()) {
        relationship.getPropertyKeys();
        relationship.getStartNode();
      }
    }
  }
  return "Warmed up and ready to go!";
}

从 3.0 版本开始,并包含 APOC,现在可以通过运行存储过程来预热缓存

CALL apoc.warmup.run()

这在许多方面都有帮助。除了纯粹的性能提升之外,它还有助于缓解由于查询滞后而导致的上游问题。例如,如果节点很忙,并且您的负载均衡器/代理的超时时间非常短,如果图中还没有任何内容在内存中,那么最初可能会出现集群不可用的情况。如果缓存被预热,则短超时在冷集群启动时不应成为问题。