08 | Raft算法(二):如何复制日志?

通过上一讲的学习,你应该知道 Raft 除了能实现一系列值的共识之外,还能实现各节点日志的一致,不过你也许会有这样的疑惑:“什么是日志呢?它和我的业务数据有什么关系呢?”

想象一下,一个木筏(Raft)是由多根整齐一致的原木(Log)组成的,而原木又是由木质材料组成,所以你可以认为日志是由多条日志项(Log entry)组成的,如果把日志比喻成原木,那么日志项就是木质材料。

在 Raft 算法中,副本数据是以日志的形式存在的,领导者接收到来自客户端写请求后,处理写请求的过程就是一个复制和应用(Apply)日志项到状态机的过程。

那 Raft 是如何复制日志的呢?又如何实现日志的一致的呢?这些内容是 Raft 中非常核心的内容,也是我今天讲解的重点,我希望你不懂就问,多在留言区提出你的想法。首先,咱们先来理解日志,这是你掌握如何复制日志、实现日志一致的基础。

如何理解日志?

刚刚提到,副本数据是以日志的形式存在的,日志是由日志项组成,日志项究竟是什么样子呢?

其实,日志项是一种数据格式,它主要包含用户指定的数据,也就是指令(Command),还包含一些附加信息,比如索引值(Log index)、任期编号(Term)。那该怎么理解这些信息呢?

指令:一条由客户端请求指定的、状态机需要执行的指令。你可以将指令理解成客户端指定的数据。

索引值:日志项对应的整数索引值。它其实就是用来标识日志项的,是一个连续的、单调递增的整数号码。

任期编号:创建这条日志项的领导者的任期编号。

从图中可以看到,一届领导者任期,往往有多条日志项。而且日志项的索引值是连续的,这一点需要注意。

讲到这儿你可能会问:不是说 Raft 实现了各节点间日志的一致吗?那为什么图中 4 个跟随者的日志都不一样呢?日志是怎么复制的呢?又该如何实现日志的一致呢?别着急,接下来咱们就来解决这几个问题。先来说说如何复制日志。

如何复制日志?

你可以把 Raft 的日志复制理解成一个优化后的二阶段提交(将二阶段优化成了一阶段),减少了一半的往返消息,也就是降低了一半的消息延迟。那日志复制的具体过程是什么呢?

首先,领导者进入第一阶段,通过日志复制(AppendEntries)RPC 消息,将日志项复制到集群其他节点上。

接着,如果领导者接收到大多数的“复制成功”响应后,它将日志项应用到它的状态机,并返回成功给客户端。如果领导者没有接收到大多数的“复制成功”响应,那么就返回错误给客户端。

学到这里,有同学可能有这样的疑问了,领导者将日志项应用到它的状态机,怎么没通知跟随者应用日志项呢?

这是 Raft 中的一个优化,领导者不直接发送消息通知其他节点应用指定日志项。因为领导者的日志复制 RPC 消息或心跳消息,包含了当前最大的,将会被提交(Commit)的日志项索引值。所以通过日志复制 RPC 消息或心跳消息,跟随者就可以知道领导者的日志提交位置信息。

因此,当其他节点接受领导者的心跳消息,或者新的日志复制 RPC 消息后,就会将这条日志项应用到它的状态机。而这个优化,降低了处理客户端请求的延迟,将二阶段提交优化为了一段提交,降低了一半的消息延迟。

为了帮助理解,画了一张过程图,然后再走一遍这个过程,这样可以更加全面地掌握日志复制。

1. 接收到客户端请求后,领导者基于客户端请求中的指令,创建一个新日志项,并附加到本地日志中。

2. 领导者通过日志复制 RPC,将新的日志项复制到其他的服务器。

3. 当领导者将日志项,成功复制到大多数的服务器上的时候,领导者会将这条日志项应用到它的状态机中。

4. 领导者将执行的结果返回给客户端。

5. 当跟随者接收到心跳信息,或者新的日志复制 RPC 消息后,如果跟随者发现领导者已经提交了某条日志项,而它还没应用,那么跟随者就将这条日志项应用到本地的状态机中。

不过,这是一个理想状态下的日志复制过程。在实际环境中,复制日志的时候,你可能会遇到进程崩溃、服务器宕机等问题,这些问题会导致日志不一致。那么在这种情况下,Raft 算法是如何处理不一致日志,实现日志的一致的呢?

如何实现日志的一致?

在 Raft 算法中,领导者通过强制跟随者直接复制自己的日志项,处理不一致日志。也就是说,Raft 是通过以领导者的日志为准,来实现各节点日志的一致的。具体有 2 个步骤。

首先,领导者通过日志复制 RPC 的一致性检查,找到跟随者节点上,与自己相同日志项的最大索引值。也就是说,这个索引值之前的日志,领导者和跟随者是一致的,之后的日志是不一致的了。

然后,领导者强制跟随者更新覆盖的不一致日志项,实现日志的一致。

详细地走一遍这个过程(为了方便演示,我们引入 2 个新变量)。

PrevLogEntry:表示当前要复制的日志项,前面一条日志项的索引值。比如在图中,如果领导者将索引值为 8 的日志项发送给跟随者,那么此时 PrevLogEntry 值为 7。

PrevLogTerm:表示当前要复制的日志项,前面一条日志项的任期编号,比如在图中,如果领导者将索引值为 8 的日志项发送给跟随者,那么此时 PrevLogTerm 值为 4。

1. 领导者通过日志复制 RPC 消息,发送当前最新日志项到跟随者(为了演示方便,假设当前需要复制的日志项是最新的),这个消息的 PrevLogEntry 值为 7,PrevLogTerm 值为 4。

2. 如果跟随者在它的日志中,找不到与 PrevLogEntry 值为 7、PrevLogTerm 值为 4 的日志项,也就是说它的日志和领导者的不一致了,那么跟随者就会拒绝接收新的日志项,并返回失败信息给领导者。

3. 这时,领导者会递减要复制的日志项的索引值,并发送新的日志项到跟随者,这个消息的 PrevLogEntry 值为 6,PrevLogTerm 值为 3。

4. 如果跟随者在它的日志中,找到了 PrevLogEntry 值为 6、PrevLogTerm 值为 3 的日志项,那么日志复制 RPC 返回成功,这样一来,领导者就知道在 PrevLogEntry 值为 6、PrevLogTerm 值为 3 的位置,跟随者的日志项与自己相同。

5. 领导者通过日志复制 RPC,复制并更新覆盖该索引值之后的日志项(也就是不一致的日志项),最终实现了集群各节点日志的一致。

从上面步骤中你可以看到,领导者通过日志复制 RPC 一致性检查,找到跟随者节点上与自己相同日志项的最大索引值,然后复制并更新覆盖该索引值之后的日志项,实现了各节点日志的一致。需要你注意的是,跟随者中的不一致日志项会被领导者的日志覆盖,而且领导者从来不会覆盖或者删除自己的日志。

内容小结

本节主要了解了在 Raft 中什么是日志、如何复制日志、以及如何处理不一致日志等内容。希望你明确这样几个重点。

在 Raft 中,副本数据是以日志的形式存在的,其中日志项中的指令表示用户指定的数据。

兰伯特的 Multi-Paxos 不要求日志是连续的,但在 Raft 中日志必须是连续的。而且在 Raft 中,日志不仅是数据的载体,日志的完整性还影响领导者选举的结果。也就是说,日志完整性最高的节点才能当选领导者。

Raft 是通过以领导者的日志为准,来实现日志的一致的。

学完本节你可以看到,值的共识和日志的一致都是由领导者决定的,领导者的唯一性很重要,那么如果我们需要对集群进行扩容或缩容,比如将 3 节点集群扩容为 5 节点集群,这时候是可能同时出现两个领导者的。这是为什么呢?在 Raft 中,又是如何解决这个问题的呢?会在下一讲带你了解。

课堂思考

我提到,领导者接收到大多数的“复制成功”响应后,就会将日志应用到它自己的状态机,然后返回“成功”响应客户端。如果此时有个节点不在“大多数”中,也就是说它接收日志项失败,那么在这种情况下,Raft 会如何处理实现日志的一致呢?

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式计算是计算机科学中一个研究方向,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给多个计算机进行处理,zui后把这些计算结果综合起来得到zui终的结果。分布式网络存储技术是将数据分散地存储于多台独立的机器设备上。分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,不但解决了传统集中式存储系统中单存储服务器的瓶颈问题,还提高了系统的可靠性、可用性和扩展性。 分布式计算与互联网的普及随着计算机的普及,个人电脑开始进入千家万户。与之伴随产生的是电脑的利用问题。越来越多的电脑处于闲置状态,即使在开机状态下CPU的潜力也远远不能被完全利用。我们可以想象,一台家用的计算机将大多数的时间花费在“等待”上面。即便是使用者实际使用他们的计算机时,处理器依然是寂静的消费,依然是不计其数的等待(等待输入,但实际上并没有做什么)。互联网的出现, 使得连接调用所有这些拥有闲置计算资源的计算机系统成为了现实。  分布式计算项目那么,一些本身非常复杂的但是却很适合于划分为大量的更小的计算片断的问题被提出来,然后由某个研究机构通过大量艰辛的工作开发出计算用服务端和客户端。服务端负责将计算问题分成许多小的计算部分,然后把这些部分分配给许多联网参与计算的计算机进行并行处理,zui后将这些计算结果综合起来得到zui终的结果。 当然,这看起来也似乎很原始、很困难,但是随着参与者和参与计算的计算机的数量的不断增加, 计算计划变得非常迅速,而且被实践证明是的确可行的。一些较大的分布式计算项目的处理能力已经可以达到甚而超过世界上速度zui快的巨型计算机。 您也可以选择参加某些项目以捐赠的 CPU内核处理时间,您将发现您所提供的 CPU 内核处理时间将出现在项目的贡献统计中。您可以和其他的参与者竞争贡献时间的排名,您也可以加入一个已经存在的计算团体或者自己组建一个计算小组。这种方法很利于调动参与者的热情。  参与计算随着民间的组队逐渐增多, 许多大型组织(例如公司、学校和各种各样的网站)也开始了组建自己的战队。同时,也形成了大量的以分布式计算技术和项目讨论为主题的社区,这些社区多数是翻译制作分布式计算项目的使用教程及发布相关技术性文章,并提供必要的技术支持。 那么谁可能加入到这些项目中来呢? 当然是任何人都可以! 如果您已经加入了某个项目,而且曾经考虑加入计算小组, 您将在中国分布式计算总站及论坛里找到您的家。任何人都能加入任何由我站的组建的分布式计算小组。希望您在中国分布式总站及论坛里发现乐趣。 参与分布式计算——一种能充分发挥您的个人电脑的利用价值的zui有意义的选择——只需要下载有关程序,然后这个程序会以zui低的优先度在计算机上运行,这对平时正常使用计算机几乎没有影响。如果你想利用计算机的空余时间做点有益的事情,还犹豫什么?马上行动起来吧,你的微不足道的付出或许就能使你在人类科学的发展史上留下不小的一笔呢。 raft算法之所以容易理解,其一是他将一致性问题划分成几个子问题,这几个子问题都是独立、可理解和解释的。从传统的思维来讲,对于一个复杂的系统或者工程,都是大化小,分解实现,然后去尝试融合解决整体逻辑。包括CS系统的设计也是如此。 一致性算法的目标 1.安全性:在非拜占庭错误情况下,包括网络延迟、分区、丢包、冗余和乱序等错误都可以保证正确。2.可用性:只要集群中大多数节点处于runing,并且不分区,和客户端能通信,那么我们需要保证这个集群可用。3.对于数据同步,小部分慢节点的不会影响系统性能。因为对于日志复制,我们如果等待所有节点响应,那么系统的性能会存在短板效应。 说白了,就是如果一个集群中,如果大多数节点可用(网络、服务),那么通过raft算法,我们就能保证整个系统可用(可处理请求,数据一致性)。后面我们主要研究的就是raft是如何做到的。首先我们要知道,Raft算法将其问题划分为 领导选举 日志复制 安全性 对于一个集群只有一个leader(领导),那么我们就很容易理解。只要领导操作同步到对应的followers(跟随者),数据必然一致。当leader宕机,需要进行领导选举。 日志复制其实就是同步操作数据的过程。leader将操作日志同步到其他节点。安全性:如何安全的同步,在不同的情况,我们都能保证一致性,这也就是安全性需要考虑的问题。 其实就是如此,raft首先假设了领导选举。然后实现了日志复制,zui后在安全问题上解决上面的漏洞问题。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值