Apache Ratis的Ratis Server主从同步机制

前言


前段时间,笔者讲述了关于Raft协议内部投票过程的一个具体实现,实现过程取自于Apache Ratis项目内部的代码。本文笔者将再来阐述Apach Ratis项目内部Ratis Server的主从服务同步机制。Ratis Server在经过Raft协议投票选举出Leader之后,是如何进行Leader、Follower间的数据同步的呢?更确切地来说,是如何保持主从之间数据的一致性的呢?

主从服务间的数据同步常用作法


这里我们所说的主从服务,它所指的是”有状态“的服务,并不是完全无状态只是为了临时快速切换的所谓的“主从服务”。对于这种“有状态”信息的服务,我们的目标是让这些“状态”信息及时同步到其它Follow的服务内。于是,我们可以想到以下一些同步方法:

  • 主服务直接同步状态信息到多个备服务中。这种方案的弊端在于主服务没有持久化未及时同步到Follow服务的状态信息,这会导致系统服务突然crash导致状态信息丢失的情况。
  • 主服务写出状态信息到外部存储中,由备服务再从外部存储中同步状态信息。这里外部存储的引入可以保证状态信息不丢失,但是此方案因为引入了外部存储的关系,在整个服务交互上会比第一种方案复杂一些。这种方案在实际工作的系统内经常能碰到,例如HDFS的QJM机制,还有例如其它一些存储系统的WAL机理等等。

本文笔者将要阐述的Ratis Server间的主从同步在本质原理上也属于第二套方案,不过在里面额外引入了状态机的角色,状态机将会和WAL进行一些额外的交互操作,下面我们来了解这方面的主要内容。

Ratis Server主从服务的状态同步机制


状态机的原语定义


对于存储系统的主从服务同步来说,我们所指的“状态”一致具体指的是其中元数据的一致性,例如文件,目录属性信息等等。对于这里的状态而言,就会有对应改变这个“状态”的transaction操作,在实际系统中比如客户端的一个个请求操作。

因此状态机理论可以完全适用于我们当前的主从服务的同步机制,不过会有以下的原语定义:

  • 对于存储系统服务来说,它的StateMachine 内部维护State可以是一个文件map信息结构,包含了所有文件的元数据信息。当我们对这个map进行更新的时候,也就意味着我们将更新State从State1到State2。
  • 客户端的请求操作,对于StateMachine而言,则是一个log entry。不过只有被提交过的committed log,才能被apply到StateMachine中,然后进行State的改变。这里“被提交”的概念是指我的log entry已经被半数以上的Follower服务所接受并应用。

Ratis Server内部角色服务


下面我们来看Ratis Server内部服务的定义,如上文所介绍的,至少已经有2个角色,StateMachine和WAL(Transaction Log)。除此之外,还有以下的角色服务:

  • RetryCache,对于客户端而言,Ratis Sever内部有RetryCache,为了避免客户端发起重复的请求操作。
  • Raft Log,Raft Log可以理解为是Ratis Server的WAL,每次用户的操作会被转化为transaction log然后被写入到Raft Log中,如果log写满了,则会新创建Raft Log文件进行写入。
  • LogAppender,此角色服务是将Leader内最新的transaction log发送到远端的各个Follower服务中,并获取返回结果。然后及时更新Raft Log的commit index。
  • StateMachineUpdater,此角色根据Raft Log的commit记录,及时apply 最新committed的log entry到StateMachine中,然后purge掉commit index之前的log文件。同时它会定期给StateMachine做snapshot操作。StateMachineUpdater的功能有点类似于Checkpoint的角色功能。

在Ratis Server现有的主从同步中,以上角色服务是按照如下图所示进行协调工作的:
在这里插入图片描述

上述过程的核心点在于StateMachine只会apply那些成功提交的transaction log,所以我们能够确保主从服务状态的一致性。

posted @ 2020-01-12 19:08  回眸,境界  阅读(772)  评论(0编辑  收藏  举报