在并发合并操作(REST )中,我遇到了死锁问题。我有一个用一些元数据处理文本的函数,对于元数据字典中的每个项,我正在执行一个合并,以添加一个节点或将文本节点与元数据节点连接起来。当消息速率在每秒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我正在通过芹菜运行上面的Python (对于那些不熟悉芹菜的人来说,它是一个分布式任务队列)。当问题第一次出现时,我在单个事务中执行上述操作,并且由于死锁异常而失败了很多次。我最初的想法是用Redis在功能级别上实现一个分布式阻塞锁。然而,这在我的应用程序中造成了一个瓶颈。
接下来,我从单个Cypher事务中切换了几个原子事务,如上面所示,并删除了锁。这解决了瓶颈,并大大减少了死锁异常的数量,但它们仍然在发生,尽管是在减少的级别上。
图形数据库并不是我真正喜欢的东西,所以我对Neo4j和Cypher的输入和输出没有太多的经验。我在现有节点的uuid的Redis中有一个次要索引,所以在合并之前有一个预处理步骤来尝试并保持图形访问权限。有什么明显的解决办法需要我去尝试吗?也许有一些方法可以在图端排队操作,或者我忽略了一些服务器优化?任何关于在哪里寻找的建议都将不胜感激。谢谢!
发布于 2016-02-25 21:52:03
我想我发现了这个问题,主要是根本就没有问题。这就是:
企业版的Neo4j比Community有一个替代的锁管理器,用于在高CPU计数计算机上提供可伸缩的锁定。 Enterprise使用一种不需要(很多)同步的死锁检测算法,这为它提供了一些非常理想的可伸缩性属性。缺点是它有时会发现假阳性。这在生产使用中通常不会发生,但在压力测试单个操作中会变得明显。在这些场景中,CPU缓存失效的次数要低得多,企业锁管理器需要跨核进行通信。 由于死锁检测错误是一个安全的重试错误,用户需要在所有应用程序代码中处理这些错误,因为在任何时候都可能存在合法的死锁,因此这种行为实际上是为了获得可伸缩性。
我只是抓住了异常,几秒钟后再试一次,现在:

发布于 2016-02-25 17:41:32
好吧,再考虑一下这个问题之后,我意识到执行查询的方式效率很低,可以通过一些重构来完成。由于所有查询都在相同的一般上下文中,因此没有理由单独执行它们,甚至没有理由打开事务并以这种方式执行它们。
相反,我更改了函数以遍历条件,并将查询字符串连接到一个长字符串中,并将我需要的params添加到param字典中。所以,现在,在最后只有一个执行,只有一个语句。这也去掉了一些“匹配”语句。
但是,由于仍然有一些死锁异常被抛出,此修复并不完全修复该问题。
https://stackoverflow.com/questions/35618483
复制相似问题