2014-10-01 7 views
21

TL; DR: Ich verliere entweder meine Meinung, oder die Transaktionen von neo4j sind leicht kaputt. Offenbar sind nicht festgeschriebene Knoten außerhalb von festgeschriebenen Transaktionen mit fehlenden Eigenschaften verfügbar - oder etwas Ähnliches.Sind die Chiffriertransaktionen von neo4j kaputt?

Unsere node.js App verwendet neo4j. Ein Teil davon muss eindeutige IDs generieren. Wir haben die folgende Abfrage, die den letzten :Id-Typ-Knoten suchen und versuchen soll, einen neuen :Id-Knoten mit last_uuid+1 zu committen.

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 

Es gibt auch eine Einschränkung:

neo4j-sh (?)$ schema 
Indexes 
    ON :Id(uuid) ONLINE (for uniqueness constraint) 

Constraints 
    ON (id:Id) ASSERT id.uuid IS UNIQUE 

Und die DB mit einem (:Id{uuid:1}) initialisiert wird, um diese Freude kurbelt.

Der App-Code versucht im Prinzip die obige Abfrage, bis sie erfolgreich ist. Wenn zwei oder mehr ID-Erstellungsanfragen gleichzeitig ausgelöst werden, wird nur einer von ihnen ausgeführt, der Rest würde fehlschlagen und vom App-Code erneut versucht werden.

Das hat funktioniert, bis wir es parallel versucht haben.

Der Code begann, Daten ohne UUID zurückzuliefern. Nach vielen Untersuchungen stellt sich heraus, dass der Write-Teil der Anfrage (CREATE ...) irgendwie eine: ID von MATCH erhält, die keine .uuid (oder andere) Eigenschaften hat. Dies sollte nicht möglich sein. Dies ist der einzige Code, der auf diesen Knoten ausgeführt wird.

Das seltsamste (vielleicht) Sache ist, dass, wenn ich i ‚s nodeid speichern, um diesen Knoten in der DB zu lokalisieren, es existiert tatsächlich und eine .uuid Eigenschaft hat.

Um dieses Verhalten zu isolieren habe ich einen PoC geschrieben: neo4j-transaction-test Es sollte wirklich einfach sein, mit nodejs zu laufen.

Es ist im Grunde ein bisschen mehr als der obige Code - versucht, die ID, prev_label, prev_nodeid und prev_uuid zu den vorherigen Knoten (i) -Werte zu erstellen. Es führt die Abfrage für jede GET-Request auf localhost erhält: 9339 und Ausgänge:

> 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) 

, wenn die Dinge immer gleichzeitig starten, kann Abfragen fehlschlagen:

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

, die zu erwarten ist, und sie sind wiederholt. Wenn wir den Server mit ein paar reqs pro Sekunde „Slam“ (ab -n 1000 -c 10 http://localhost:9339/), werden wir schließlich sehen:

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

Error: Empty UUID received 

(und schließlich, meine ich fast sofort) Ein Knoten kommt zurück, ohne UUID, prev_uuid oder prev_label. this_nodeid und prev_nodeid beziehen sich auf die interne ID von neo4j. Wenn wir diese nach oben schauen, mit den vorherigen (i) Id Knoten starten (durch 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 

Es ist genau so, wie es sein sollte. .uuid und alle.Der neue ist in der Tat geschaffen wie es oben zurückgegeben:

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 

Keine prev_label oder prev_uuid. Wie ist das möglich? Was vermisse ich? Ist ein unvollständig: Id-Knoten in meine Abfrage eindringen?

Ich habe versucht, neu zu starten, wischen die Daten dir, Neustart nach dem Abwischen der Daten dir, fegte die Protokolle (nichts interessantes oder sogar langweilig, aber zur richtigen Zeit - wenn das obige passiert). Ich bin jetzt an dem Punkt, wo ich mein Verständnis darüber in Frage stelle, wie das funktionieren soll.

Dies ist am 12.04 mit neo4j 2.1.1. More Version Info und Neo4j startup/shutdown logs.

Ich bin mir bewusst, dass dies keine optimale Möglichkeit zum Erstellen von UUIDs ist. In dieser Frage geht es darum zu verstehen, wie diese Ergebnisse möglich sind, wenn die Transaktionen von neo4j wie erwartet funktionieren.

+0

Ich verstehe das. Wenn wir bei neo4j bleiben (nicht sehr wahrscheinlich), wird der ID-Generierungscode von der DB entfernt. Ich möchte trotzdem wissen, wie ich dieses Ergebnis sehe - es deutet auf etwas hin, das mit Chiffriertransaktionen gebrochen ist. –

+3

Anstatt Create haben Sie Merge (Superior Locking) verwendet? Könnten Sie auch den Neo4J-Node.js-Code herausnehmen und versuchen, den Transaktionsendpunkt direkt zu treffen, um das herauszudiskutieren (http://docs.neo4j.org/chunked/stable/rest-api-transactional.html), wie ich denke (inoffiziell) Die Knotenbibliothek trifft den alten Endpunkt (Ihr Neo ist neuartig, Ihr Knoten ist nicht). Sie können dann auch die rohe Antwort sehen. – JohnMark13

+0

@TasosBitsios gab es irgendeine Lösung dazu? – JohnMark13

Antwort

1

Wir bemerkten ein ähnliches Problem in Neo4J während gleichzeitiger transaktionaler Schreibvorgänge und es wurde ein Update in Neo4J 2.2.5 eingeführt, um dies zu beheben (wir haben Enterprise-Unterstützung und ein Ticket angehoben, um dies zu beheben). Möglicherweise haben Sie nicht genau das gleiche Problem, aber es könnte einen Versuch wert sein, es erneut mit 2.2.5 zu versuchen, um zu sehen, ob es immer noch ein Problem ist.

Wie Sie sagten, gibt es bessere Möglichkeiten, IDs zu generieren. Auch sollten Sie MAX verwenden, um die neueste statt LIMIT und ORDER BY zu bekommen, aber das ist neben dem Punkt auch ;-).

Viel Glück.

Verwandte Themen