知识库

Neo4j 的提交过程说明

本文将尝试引导您了解 Neo4j 在单实例和因果集群下的提交与复制过程。

 

单实例

当您调用 tx.commit() 时,事务会经过存储引擎,该引擎会将事务转换为事务表示(Transaction Representation)。这类似于转储事务日志时得到的内容,包含该事务生成的所有命令。

Command[
-Node[0,used=false,rel=-1,prop=-1,labels=Inline(0x0:[]),light,secondaryUnitId=-1]
  +Node[0,used=true,rel=-1,prop=-1,labels=Inline(0x0:[]),light,secondaryUnitId=-1]
]

1574356393567

图片 1 - 存储引擎

在单实例上,这个事务表示随后会传递给事务提交过程(Transaction Commit Process),该过程会将事务写入事务日志,内部会调用 appendToLog()。随后,事务表示会进入记录存储引擎(Record Store Engine),并将事务持久化到磁盘(applyToStore())。

applyToStore() 并不一定与 appendToLog() 同时发生,而是发生在检查点操作期间或脏页从页面缓存中刷出时。

1574356466764

图片 2 - 事务提交过程

1574356588784

图片 3 - 记录存储引擎

这就是单实例的处理流程,相对简单。自然,它不涉及任何 RAFT 组件。

因果集群

对于因果集群(Causal Cluster),工作将在 Leader 上完成。流程基本相同,但事务提交过程会在将事务刷入日志之前被拦截。

1574356830851

图片 4 - 事务提交过程

事务表示被复制事务提交过程(Replicated Transaction Commit Process)拦截,并将其转换为 Raft 消息(commit())。随后由名为 Raft Replicator 的组件进行复制(replicate()),复制方式如下:

  1. Leader 向 Followers 发送 Append 请求,告知有新消息。

  2. Followers 将该消息追加到自己的 RAFT 日志,并回复已追加的响应。

  3. Leader 收到该响应后再发送 Commit 消息,表示双方均已就绪,可安全提交。

1574357483281

图片 5 - 复制

一些考虑事项

  • 在此过程中,您可能会看到 Leader 向自身发送 Append 请求。这是预期行为,因为 Leader 同时也是集群的 Core 实例,需要将消息追加到自己的 RAFT 日志中。

  • 流程为:追加 > 追加响应 > 提交 > 追加 (…​)

  • 集群只需要多数实例对消息进行 ACK。出于此原因,某些发送给 Followers 的消息可能已经被提交。

  • 我们使用消息流水线(message pipelining),即 Commit 消息可以同时携带 Append,以加快处理速度。

  • 网络中的所有消息都被视为 心跳

完成上述操作后,事务表示会进入我们称作复制事务状态机(Replicated Transaction State Machine)的事务表示队列(applyCommand()),该状态机记录事务及其在存储中应用的顺序。

1574357973780

图片 6 - 复制事务状态机

随后,这些 事务表示 将再次经过提交过程,进而回到 事务提交过程(图片 2)以冲刷到事务日志,最终写入存储(图片 3)。

© . This site is unofficial and not affiliated with Neo4j, Inc.