知识库

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 组件。

因果集群

对于因果集群,工作将在领导者节点上完成。过程中的所有内容都相同,但事务提交过程在将事务刷新到日志之前会被拦截。

1574356830851

图像 4 - 事务提交过程

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

  1. 领导者节点将向跟随者节点发送一个追加请求,表明它收到了一条新消息

  2. 跟随者节点将该消息追加到它们自己的 RAFT 日志中,并发送响应,表明消息已追加

  3. 领导者节点收到该消息后,会发送一条提交消息,表明两端一切正常,可以安全提交

1574357483281

图像 5 - 复制

一些注意事项

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

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

  • 集群只需要大多数实例来确认消息。因此,某些发送给可能已提交消息的跟随者节点的消息可能会被丢弃。

  • 我们使用消息流水线,其中提交消息也可以包括一个追加请求,以实现更快的处理。

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

发生这种情况后,事务表示将经过一个事务表示队列,我们将其称为复制事务状态机 (applyCommand()),该队列跟踪事务及其应用于存储的顺序。

1574357973780

图像 6 - 复制事务状态机

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