如何诊断锁定问题
自 Neo4j 3.4 版本以来,可以更好地理解并发查询导致的锁定问题。本知识库文章不会详细介绍 Neo4j 中锁定的基础知识。我们假设您同时运行大量查询——可能是相同的参数化查询,也可能是不同的查询。这些查询的典型执行时间远高于您的预期——您会认为 Neo4j “很慢”。实际上,这种现象的原因可能是您的查询试图获取公共节点上的锁,因此它们需要等待直到锁持有者释放锁。等待公共锁的查询实际上是串行执行的。
在之前的 Neo4j 版本中,查询日志记录功能允许添加与查询处于等待状态(无论是等待锁还是等待 I/O)的时间长度相关的信息。这可以通过 neo4j.conf 参数 dbms.logs.query.time_logging_enabled=true
开启。然而,这只提供了总等待时间的信息,而无法深入了解是哪个竞争节点或关系可能导致了它。
从 Neo4j 3.4 版本开始,以及随着新的存储过程 dbms.listTransactions()
的引入,可以更好地理解延迟的原因。为了通过 2 个 cypher-shell 连接演示这些过程,请运行以下 Cypher
session1: merge (n:Lock {id:1}) set n.age=20 with n call apoc.util.sleep(200000) return n; session2: Match (n:Lock {id:1}) set n.age=85 return n;
第一个会话将把标记为 :Lock 且 id=1 的节点的 age
属性设置为 20,然后休眠 200 秒(从而保持对该节点的锁定)。第二个会话将尝试更新同一个节点,并将其 age
属性设置为 85,但在 200 秒内将被阻塞。
在这 200 秒内,通过 Neo4j Browser 运行 call dbms.listTransactions() yield transactionId, startTime, currentQueryId, currentQuery, status
将返回类似如下的输出
从该输出中,我们可以看到 transaction-1381/query-1378 报告其状态为 Blocked by: [transaction-1380],并且 transaction-1380 也列在输出中,两个事务都描述了 currentQuery。
此外,运行 call dbms.listActiveLocks('<currentQueryId>');
,例如 call dbms.listActiveLocks('query-1377');
将返回类似如下的输出
从上述输出中,我们看到 query-1377 在 id(n)=8432 的节点上有一个 EXCLUSIVE NODE 锁。
有了这两个过程,您就拥有了强大的工具来了解哪些节点/关系可能是锁竞争的来源。
此页面有帮助吗?