2014-10-01 14 views
21

TL; DR: Tôi đang mất trí hoặc giao dịch của neo4j bị hỏng một chút. Có vẻ như các nút không được cam kết có sẵn bên ngoài các giao dịch đã cam kết, với các thuộc tính bị thiếu - hoặc một cái gì đó không kém phần lạ.Giao dịch cypher của neo4j có bị hỏng không?

Ứng dụng node.js của chúng tôi sử dụng neo4j. Một phần của nó phải tạo ra các ID duy nhất. Chúng tôi có truy vấn cypher sau đây nhằm xác định nút :Id -type cuối cùng và cố gắng thực hiện nút :Id mới với 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 

Ngoài ra còn có một hạn chế:

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

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

Và DB được khởi tạo với một (:Id{uuid:1}) để khởi động niềm vui này.

Mã ứng dụng về cơ bản sẽ thử lại truy vấn trên cho đến khi thành công. Nếu hai hoặc nhiều yêu cầu tạo Id nhấn cùng một lúc, chỉ một yêu cầu sẽ được thực hiện, phần còn lại sẽ thất bại và được thử lại bằng mã ứng dụng.

Tính năng này hoạt động, cho đến khi chúng tôi thử song song.

Mã bắt đầu trả về dữ liệu mà không có uuid. Sau rất nhiều điều tra, nó chỉ ra rằng phần viết của truy vấn (CREATE ...) bằng cách nào đó nhận được một: Id từ MATCH không có thuộc tính .uuid (hoặc khác). Điều này không thể thực hiện được. Đây là mã duy nhất hoạt động trên các nút đó.

Các kỳ lạ (có lẽ) điều, là nếu tôi tiết kiệm i 's nodeid để xác định vị trí nút đó trong DB, nó thực sự tồn tại có một tài sản .uuid.

Để cô lập hành vi này, tôi đã viết một PoC: neo4j-transaction-test Nó sẽ thực sự đơn giản để chạy với nútj. Nó là cơ bản một chút chút nhiều hơn mã trên - cố gắng để tạo ra các Id, thiết lập prev_label, prev_nodeid, và prev_uuid với các giá trị Node (i) trước đó của nó. Nó chạy truy vấn cho mỗi GET yêu cầu nó nhận được trên localhost: 9339 và kết quả đầu ra:

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

khi mọi thứ bắt đầu nhận đồng thời, các truy vấn có thể thất bại:

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

mà là để được mong đợi, và họ là đã thử lại. Nếu chúng ta "slam" máy chủ với một vài reqs mỗi giây (ab -n 1000 -c 10 http://localhost:9339/), chúng tôi cuối cùng sẽ thấy:

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

Error: Empty UUID received 

(và cuối cùng, tôi muốn nói gần như ngay lập tức) Một nút trở lại, mà không uuid, prev_uuid hoặc prev_label. this_nodeid và prev_nodeid tham chiếu đến id nội bộ của neo4j. Nếu chúng tôi xem xét những điều này, bắt đầu với nút Id trước đó (i) (bở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 

Chính xác như vậy. .uuid và tất cả.Cái mới thực sự được tạo ra giống như nó được trả lại ở trên:

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 

Không có prev_label hoặc prev_uuid. Sao có thể như thế được? Tôi đang thiếu gì? Là một không đầy đủ: nút Id bị rò rỉ vào truy vấn của tôi?

Tôi đã thử khởi động lại, xóa thư mục dữ liệu, khởi động lại sau khi xóa thư mục dữ liệu, ghi nhật ký (không có gì thú vị hoặc thậm chí là nhàm chán nhưng vào đúng thời điểm - khi xảy ra ở trên). Bây giờ tôi đang ở điểm mà tôi đang đặt câu hỏi về sự hiểu biết của tôi về cách thức hoạt động của nó.

Đây là ngày 12.04 với neo4j 2.1.1. More Version InfoNeo4j startup/shutdown logs.

Tôi biết rằng đây không phải là cách tối ưu để tạo UUID. Câu hỏi này là về sự hiểu biết làm thế nào các kết quả này là có thể nếu các giao dịch của neo4j hoạt động như mong đợi.

+0

Tôi hiểu điều đó. Nếu chúng ta gắn bó với neo4j (không phải rất có thể) thì mã tạo mã ID sẽ bị xóa khỏi DB. Tôi vẫn muốn biết làm thế nào tôi nhìn thấy kết quả này mặc dù - nó chỉ ra một cái gì đó bị phá vỡ với các giao dịch cypher. –

+3

Thay vì Tạo bạn đã sử dụng Hợp nhất (khóa vượt trội)? Bạn cũng có thể lấy mã Node.js của Neo4J ra ngoài và thử nhấn trực tiếp điểm cuối giao dịch để loại trừ (http://docs.neo4j.org/chunked/stable/rest-api-transactional.html) như tôi nghĩ rằng (không chính thức) Node thư viện chạm vào điểm cuối di sản (Neo của bạn là mới, Node của bạn không). Bạn cũng có thể xem phản hồi thô. – JohnMark13

+0

@TasosBitsios có bất kỳ giải pháp nào cho vấn đề này không? – JohnMark13

Trả lời

1

Chúng tôi nhận thấy sự cố tương tự trong Neo4J trong quá trình giao dịch đồng thời và đã có bản sửa lỗi được giới thiệu trong Neo4J 2.2.5 để giải quyết vấn đề này (chúng tôi có hỗ trợ Enterprise và đặt vé để sửa lỗi này). Bạn có thể không có chính xác cùng một vấn đề, nhưng nó có thể là giá trị cố gắng một lần nữa bằng cách sử dụng 2.2.5 để xem nếu nó vẫn là một vấn đề.

Như bạn đã nói, có nhiều cách tốt hơn để tạo id. Ngoài ra, bạn nên sử dụng MAX để nhận phiên bản mới nhất thay vì LIMITORDER BY, nhưng đó cũng là điểm ngoài ;-).

Chúc may mắn.

Các vấn đề liên quan