Transactions 是neo4j';谁的交易被破坏了?
TL;博士:我不是疯了,就是neo4j的交易有点中断。看起来,未提交的节点在提交的事务之外可用,缺少属性,或者有一些同样奇怪的东西 我们的node.js应用程序使用neo4j。它的一部分必须生成唯一的ID。我们有以下cypher查询,用于定位最后一个Transactions 是neo4j';谁的交易被破坏了?,transactions,neo4j,cypher,node-neo4j,Transactions,Neo4j,Cypher,Node Neo4j,TL;博士:我不是疯了,就是neo4j的交易有点中断。看起来,未提交的节点在提交的事务之外可用,缺少属性,或者有一些同样奇怪的东西 我们的node.js应用程序使用neo4j。它的一部分必须生成唯一的ID。我们有以下cypher查询,用于定位最后一个:Id-类型节点,并尝试提交一个新的:Id节点,该节点具有最后一个\u uuid+1 MATCH (i:Id) WITH i ORDER BY i.uuid DESC LIMIT 1 #with it like a sub-return, will
:Id
-类型节点,并尝试提交一个新的:Id
节点,该节点具有最后一个\u uuid+1
MATCH (i:Id) WITH i ORDER BY i.uuid DESC LIMIT 1 #with it like a sub-return, will "run" the rest with the last i at read-time
CREATE (n:Id {label:"Test"})
SET n.uuid = i.uuid + 1
RETURN n
还有一个限制:
neo4j-sh (?)$ schema
Indexes
ON :Id(uuid) ONLINE (for uniqueness constraint)
Constraints
ON (id:Id) ASSERT id.uuid IS UNIQUE
DB被一个(:Id{uuid:1})
初始化,以启动这个喜悦
应用程序代码基本上会重试上述查询,直到成功。如果两个或多个Id创建请求同时命中,则其中只有一个将通过,其余的将失败并由应用程序代码重试
这是有效的,直到我们同时尝试
代码开始返回没有uuid的数据。经过大量调查,结果表明查询的写入部分(CREATE…)不知何故从MATCH接收到一个:Id,它没有.uuid(或其他)属性。这是不可能的。这是在这些节点上运行的唯一代码
最奇怪(也许)的事情是,如果我保存I
的nodeid
以便在数据库中定位该节点,它实际上存在并且具有.uuid属性
为了隔离这种行为,我编写了一个PoC:使用nodejs运行应该非常简单
它基本上比上面的代码多一点-尝试创建Id,将prev_label
、prev_nodeid
和prev_uuid
设置为前一个节点的(i)值。它对在localhost:9339上收到的每个GET请求运行查询,并输出:
> node server.js
* 1412125626667 Listening on 9339
Req Id | Datetime | -> $uuid $nodeid
1 1412125631677 'GET' # When it first receives the GET request
1 1412125631710 '->' 9 60 # When neo4j returns; numbers are $uuid $node_id)
当事情开始并发时,查询可能会失败:
3 1412125777096 '(retry) (0)' 'Node 64 already exists with label Id and property "uuid"=[13]'
4 1412125777098 '(retry) (0)' 'Node 64 already exists with label Id and property "uuid"=[13]'
de[]
这是意料之中的,它们将被重试。如果我们每秒“猛击”服务器几个请求(ab-n1000-c10http://localhost:9339/
),我们最终将看到:
...
59 1412127103011 'GET'
23 1412127103024 'ERROR - EMPTY UUID' '{"this_nodeid":22,"prev_nodeid":20,"label":"Test"}'
Error: Empty UUID received
(最终,我的意思是几乎立即)一个节点返回,没有uuid、prev_uuid或prev_标签。此节点id和上一个节点id指的是neo4j的内部id。如果我们从上一个(i
)id节点(通过节点id-20)开始查找它们:
这完全是应该的.uuid
和所有。正如上面返回的一样,确实创建了新的:
neo4j-sh (?)$ match (i) where id(i)=22 return i;
+------------------------------------------------------+
| i |
+------------------------------------------------------+
| Node[22]{label:"Test",prev_nodeid:20,this_nodeid:22} |
+------------------------------------------------------+
1 row
17 ms
没有prev_标签或prev_uuid。这怎么可能?我错过了什么?是否有不完整的:Id节点泄漏到我的查询中
我尝试过重新启动、擦除数据目录、在擦除数据目录后重新启动、清除日志(没有什么有趣的,甚至没有意思,但在正确的时间——当上述情况发生时)。我现在正在质疑我对这应该如何运作的理解
这是在12.04与neo4j 2.1.1。和
我知道这不是创建UUID的最佳方式。这个问题是关于理解如果neo4j的事务按预期工作,这些结果是如何可能的。在并发事务写入期间,我们注意到neo4j中存在类似的问题,neo4j 2.2.5中引入了一个修复程序来解决这个问题(我们有企业支持,并提出了解决问题的建议)。您可能没有完全相同的问题,但可能值得使用2.2.5再试一次,看看它是否仍然是一个问题 正如您所说,有更好的方法生成ID。此外,您应该使用
MAX
来获取最新的,而不是LIMIT
和orderby
,但这也是除此之外的要点;-)
祝你好运。我明白这一点。如果我们坚持使用neo4j(不太可能),那么ID生成代码将从DB中移出。不过我还是想知道我是如何看待这个结果的——它表明密码事务出现了一些问题。您使用了Merge(高级锁定)而不是Create吗?您是否也可以取出Neo4J Node.js代码,并尝试直接命中事务端点以排除该错误(),因为我认为特定(非官方)节点库命中了遗留端点(您的Neo是新的,而您的节点不是)。您还可以看到原始响应。@TasosBitsios对此有任何解决方案吗?很抱歉延迟@JohnMark13,现实生活中遇到了阻碍。还没有任何解决方案,我想我会向neo4j团队提出GH问题。RE:MERGE,我还没有尝试过,即使它按预期工作,我仍然想知道这里发生了什么。回复:版本/API,AFAIK没有非事务性API。遗留端点将把查询包装在事务中,较新的端点将允许跨查询的事务。这并没有真正改变这个结果毫无意义的事实。你曾经发布过一个问题吗?我现在也遇到了这样或类似的事情。我打开了一个
neo4j-sh (?)$ match (i) where id(i)=22 return i;
+------------------------------------------------------+
| i |
+------------------------------------------------------+
| Node[22]{label:"Test",prev_nodeid:20,this_nodeid:22} |
+------------------------------------------------------+
1 row
17 ms