Neo4j和并发写道,如何处理死锁问题,最好是服务器端?

时间:2016-02-25 04:39:38

标签: neo4j cypher

我在并发合并操作(REST API)期间遇到了死锁问题。我有一个处理带有一些元数据的文本的函数,对于元数据字典中的每个项目,我正在执行合并以添加节点或将文本节点与元数据[n]节点连接。当消息速率大约为每秒500-1000时出现问题。

在这个特定的函数中,6个查询之间有11个合并,如下所示:

q1 = "MERGE (n:N { id: {id} }) ON CREATE SET ... ON MATCH SET "
     "WITH . MERGE (...) "
     "WITH ., . MERGE (.)-[:some_rel]->(.)"
params = {'the': 'params'}
cypher.execute(q1, params)

if some_condition:
    q2 = "MATCH (n:N { id: {id} }) ... "
         "WITH n, . MERGE (n)-[:some_rel]->(.)"
    params = {'more': 'params'}
    cypher.execute(q2, params)

 if some_condition2:
     q3
 ...
 if some_condition_n:
     qn

我通过Celery运行上面的Python(对于那些不熟悉Celery的人来说,它是一个分布式任务队列)。当问题首次出现时,我在单个事务中执行上述操作,并且由于死锁异常而导致大量失败。我最初的想法只是在Redis的功能级别实现分布式阻塞锁。但是,这会导致我的应用程序出现瓶颈。

接下来,我从单个Cypher事务中切换了几个原子事务,如上所述并删除了锁。这样可以解决瓶颈问题,并大大减少死锁异常的数量,但它们仍在发生,尽管处于降低的水平。

图形数据库并不是我真正的东西,所以我对Neo4j和Cypher的输入和输出没有太多的经验。我在Redis中有一个现有节点的uuid的二级索引,因此在合并之前有一个预处理步骤,试图保持图形访问权限。我应该尝试一些明显的解决方案吗?也许有一些方法可以在图形方面对操作进行排队,或者我可能忽略了一些服务器优化?任何关于在哪里看的建议将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

好的,在考虑了这个之后,我意识到执行查询的方式效率低下,可以通过一些重构来实现。由于所有查询都在同一个通用上下文中,因此没有理由单独执行它们,甚至没有理由打开事务并以这种方式执行它们。

相反,我更改了函数以完成条件,并将查询字符串连接成一个长字符串,并将我需要的参数添加到param字典中。所以,现在,最后只有一个执行,只有一个声明。这也取消了一些'匹配'语句。

但是,此修复程序并未完全解决此问题,因为仍有一些死锁异常被抛出。

答案 1 :(得分:1)

我认为我发现了这个问题,主要是因为开始时没有问题。 That is:

  

Neo4j的企业版有一个替代锁定管理器   社区版本,旨在提供可扩展的锁定   高CPU数的机器。

     

Enterprise Lock Manager使用死锁检测算法   不需要(很多)同步,这给了它一些非常好的   理想的可伸缩性属性。缺点是它可能   有时会发现误报。这通常不会发生   生产使用,但在压力测试个体中变得明显   操作。这些场景看到CPU缓存的流失率要低得多   失效,企业锁管理器需要进行通信   跨核心。

     

因为死锁检测错误是一个安全重试错误而用户是   期望在所有应用程序代码中处理这些,因为可能存在   任何时候合法的死锁,这种行为实际上是设计的   获得可扩展性。

我只是抓住了异常,然后在几秒后重试,现在:

success