2014-10-01 54 views
21

TL; DR:我要么失去了我的想法,要么neo4j的交易略有破裂。看起来好像未提交的节点在提交的事务之外可用,并且缺少属性 - 或者同样奇怪的东西。neo4j的密码交易是否被破坏?

我们的node.js应用程序使用neo4j。它的一部分必须生成唯一的ID。我们有以下密码查询,用于查找最后的:Id类型节点,并尝试提交一个新的:Id节点和last_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(或其他)属性。这应该是不可能的。这是在这些节点上运行的唯一代码。

最奇怪的(也许)的事情是,如果我救inodeid,以找到在数据库节点,它确实存在有.uuid属性。

为了隔离这种行为,我写了一个PoC:neo4j-transaction-test使用nodejs运行应该非常简单。

它基本上比上面的代码稍微有点 - 尝试创建Id,将prev_label,prev_nodeidprev_uuid设置为之前的Node(i)值。它运行的每一个查询GET请求接收到在localhost:9339和输出:

> 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[] 

这是可以预料的,他们是重试。如果我们“SLAM”一对夫妇每秒(ab -n 1000 -c 10 http://localhost:9339/)REQ的服务器,我们最终会看到:

... 
59 1412127103011 'GET' 
23 1412127103024 'ERROR - EMPTY UUID' '{"this_nodeid":22,"prev_nodeid":20,"label":"Test"}' 

Error: Empty UUID received 

(和最终,我的意思是几乎瞬间)节点回来,没有UUID,prev_uuid或prev_label。 this_nodeid和prev_nodeid是指neo4j的内部ID。如果我们看一下这些了,从以前的(i)标识节点(由NODEID - 20):

neo4j-sh (?)$ match (i) where id(i)=20 return i; 
+--------------------------------------------------------------------------------------------+ 
| i                       | 
+--------------------------------------------------------------------------------------------+ 
| Node[20]{uuid:10,label:"Test",prev_label:"Test",prev_uuid:9,prev_nodeid:17,this_nodeid:20} | 
+--------------------------------------------------------------------------------------------+ 
1 row 
19 ms 

正是因为它应该是。 .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_label或prev_uuid。这怎么可能?我错过了什么?是不完整的:Id节点泄漏到我的查询中?

我已经尝试重新启动,擦除数据目录,擦除数据目录后重新启动,清除日志(没有什么有趣的,甚至无聊,但在正确的时间 - 当上述情况发生时)。我现在正在质疑我对如何工作的理解。

这是在12.04与neo4j 2.1.1。 More Version InfoNeo4j startup/shutdown logs

我知道这不是创建UUID的最佳方式。这个问题是关于如果neo4j的交易如预期那样工作,那么这些结果是可能的。

+0

我明白这一点。如果我们坚持使用neo4j(不太可能),那么ID生成代码将被移出数据库。我仍然想知道我是如何看到这个结果的 - 它表明有些事情被打断了。 – 2014-10-01 15:00:50

+3

而不是创建你有使用合并(上锁)?你是否也可以将Neo4J Node.js代码取出并尝试直接敲击事务端点来排除该问题(http://docs.neo4j.org/chunked/stable/rest-api-transactional.html),因为我认为这是特别的(非官方)节点库击中传统端点(您的Neo是新的,您的节点不是)。您也可以看到原始响应。 – JohnMark13 2014-10-03 20:18:15

+0

@TasosBitsios有没有解决这个问题? – JohnMark13 2014-10-10 09:08:34

回答

1

在并发事务写入期间,我们注意到了Neo4J中的类似问题,并且在Neo4J 2.2.5中引入了一个解决此问题的解决方案(我们有企业支持并提出了一张解决此问题的方案)。你可能没有完全相同的问题,但可能值得再次尝试使用2.2.5来查看它是否仍然是一个问题。

就像你说的,有更好的方法来生成id。此外,你应该使用MAX获取最新的,而不是LIMITORDER BY,但除此之外,还;-)。

祝你好运。