知识库

Neo4j 的提交过程解释

本文将指导您了解 Neo4j 在单实例和因果集群中的提交和复制过程。

 

单实例

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

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 - 存储引擎

在单实例中,此事务表示随后传递给事务提交过程,事务提交过程将有效地将该事务写入事务日志。这在内部调用 appendToLog()。之后,事务表示将进入记录存储引擎,该引擎随后将该事务持久化到磁盘(applyToStore()

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

1574356466764

图 2 - 事务提交过程

1574356588784

图 3 - 记录存储引擎

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

因果集群

对于因果集群,工作将在 Leader 上完成。整个过程都相同,但在将事务刷新到日志之前会拦截事务提交过程

1574356830851

图 4 - 事务提交过程

事务表示被复制事务提交过程拦截,该过程将事务表示转换为 Raft 消息 (commit())。然后由一个名为 Raft 复制器 (replicate()) 的组件进行复制。复制的方式如下

  1. Leader 将向 Follower 发送一个追加消息,告知它收到新消息

  2. Follower 将该消息追加到自己的 RAFT 日志中,并发送响应确认已追加

  3. 然后 Leader 收到该消息,并发送一个提交消息,表示双方都正常,可以安全提交

1574357483281

图 5 - 复制

一些注意事项

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

  • 流程是: 追加 > 追加响应 > 提交 > 追加 (...)

  • 集群只需要大多数实例确认消息。因此,发送给 Follower 的一些消息可能已经提交过了。

  • 我们使用消息流水线技术,提交消息也可以包含追加操作,以加快处理速度。

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

在此之后,事务表示会进入一个事务表示队列,我们称之为复制事务状态机 (applyCommand()),它跟踪事务以及需要按什么顺序应用到存储中。

1574357973780

图 6 - 复制事务状态机

从那里,这些事务表示将通过提交过程,然后连接回事务提交过程(图 2),以便刷新到事务日志,最后应用到存储中(图 3)