【学习笔记】如何理解Raft中的ReadIndex?

Raft作者Diego Ongaro在其博士论文《CONSENSUS: BRIDGING THEORY AND PRACTICE》中对ReadIndex进行了相关阐述:(以下内容来自机翻)

6.4 Processing read-only queries more efficiently
      只读客户端命令只查询复制的状态机;他们不会改变它。因此,我们很自然地会问,这些查询是否可以绕过Raft日志,Raft日志的目的是以相同的顺序将更改复制到服务器的状态机。绕过日志提供了一个有吸引力的性能优势:只读查询在许多应用程序中很常见,并且需要将条目追加到日志中的同步磁盘写是很耗时的。
      但是,如果没有额外的预防措施,绕过日志可能会导致只读查询的结果陈旧。例如,一个leader可能从集群的其他部分划分出来,集群的其他部分可能已经选举了一个新的leader,并向Raft日志提交了新的条目。如果分区的leader在没有咨询其他服务器的情况下响应一个只读查询,它将返回过时的结果,这是不能线性化的。线性化要求读的结果反映读开始后一段时间的系统状态;每次读操作必须至少返回最近提交的写操作的结果。(允许陈旧读取的系统只提供可串行性,这是较弱的一致性形式。)在两个第三方Raft实现中已经发现了陈旧读取的问题,因此这个问题值得仔细关注。
      幸运的是,对于只读查询可以绕过Raft日志,但仍然可以保留线性。为此,领导者采取以下步骤:
      1. 如果leader还没有标记当前提交的条目,它将等待直到标记完成。Leader完整性属性保证Leader拥有所有提交的条目,但在其任期开始时,它可能不知道哪些是提交的条目。为了找到答案,它需要从它的术语提交一个条目。Raft通过让每个leader在其任期开始时提交一个空白的无操作条目到日志中来处理这个问题。一旦这个无操作条目被提交,leader的commit索引将在其任期内至少与任何其他服务器的索引一样大。
      2. leader将其当前提交索引保存在本地变量readIndex中。这将被用作查询操作的状态版本的下界。
      3.领导者需要确保自己没有被自己不知道的新领导者取代。它发出新一轮的心跳,并等待集群中的大多数人的确认。一旦收到这些确认信息,leader就知道在发送心跳信息的那一刻,不可能存在比这个更长的leader了。因此,readIndex当时是集群中所有服务器所见过的最大的提交索引。
      4. leader等待它的状态机至少向前推进到readIndex,这能足够满足线性化。
      5. 最后,leader对其状态机发出查询,并将结果回复给客户机。
      这种方法比将只读查询作为新条目提交到日志中更有效,因为它避免了同步磁盘写操作。为了进一步提高效率,leader可以摊销确认其leader的成本:它可以对其积累的任意数量的只读查询使用一轮心跳。
      Follower还可以帮助卸载只读查询的处理。这将提高系统的读吞吐量,并将负载从leader转移,允许leader处理更多的读写请求。然而,如果没有额外的预防措施,这些读取也会有返回过时数据的风险。例如,一个分区的follower可能在很长一段时间内都不会从leader那里接收到任何新的日志条目,或者即使follower收到了leader的心跳信号,这个leader也可能会被罢免,而且还不知道。为了安全的服务读操作,follower可以向刚刚请求当前readIndex的leader发出请求(leader会执行上面的步骤1-3);然后,Follower可以在自己的状态机上执行步骤4和步骤5,以处理累积的任意数量的只读查询。
      LogCabin在leader上实现了上述算法,并在高负载下跨多个只读查询平摊了心跳成本。LogCabin中的Follower当前不服务于只读请求。

个人理解:
只读read操作不会更改磁盘(Log)中存储的内容,没必要每次都对read操作都进行一次appendEntries,进而可以优化读操作性能。
为了避免读到旧的数据,增加了readIndex进行限制,这样Leader和Follower都可以处理Client发来的读请求。当读请求发送到Follower的时候,不需要再重定向到Leader,让Leader返回读取的结果,Follower自身就可以响应该读请求:
1)Follower向Leader索要readIndex值
2)Leader接收到索要请求后,向其他成员append空日志,以此来确定自己的leader地位并获得自己的commitIndex,返回commitIndex(readIndex=Leader.commitIndex)
3)Follower在自己的状态机上将日志至少推进到readIndex,然后查询自己的状态机,返回结果到Client。

该部分内容在LogCabin(C++)和etcd(Go)中都有相应的实现,可以去阅读该实现的源代码。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值