Raft一致性算法( 二 )


 

图 1 :复制状态机的结构 。一致性算法管理着来自客户端指令的复制日志 。状态机从日志中处理相同顺序的相同指令,所以产生的结果也是相同的 。
 
复制状态机通常都是基于复制日志实现的,如图 1 。每一个服务器存储一个包含一系列指令的日志,并且按照日志的顺序进行执行 。每一个日志都按照相同的顺序包含相同的指令,所以每一个服务器都执行相同的指令序列 。因为每个状态机都是确定的,每一次执行操作都产生相同的状态和同样的序列 。
一致性算法的任务是保证复制日志的一致性 。服务器上的一致性模块接收客户端发送的指令然后添加到自己的日志中 。它和其他服务器上的一致性模块进行通信来保证每一个服务器上的日志最终都以相同的顺序包含相同的请求,即使有些服务器发生故障 。一旦指令被正确的复制,每一个服务器的状态机按照日志顺序处理他们,然后输出结果被返回给客户端 。因此,服务器集群看起来形成了一个高可靠的状态机 。
实际系统中使用的一致性算法通常含有以下特性:
 
  • 安全性保证(绝对不会返回一个错误的结果):在非拜占庭错误情况下,包括网络延迟、分区、丢包、重复和乱序等错误都可以保证正确 。
  • 可用性:集群中只要有大多数的机器可运行并且能够相互通信、和客户端通信,就可以保证可用 。因此,一个典型的包含 5 个节点的集群可以容忍两个节点的失败 。服务器被停止就认为是失败 。它们稍后可能会从可靠存储的状态中恢复并重新加入集群 。
  • 不依赖时序来保证一致性:物理时钟错误或者极端的消息延迟只有在最坏情况下才会导致可用性问题 。
  • 通常情况下,一条指令可以尽可能快的在集群中大多数节点响应一轮远程过程调用时完成 。小部分比较慢的节点不会影响系统整体的性能 。
3 Paxos 算法的问题 
在过去的 10 年里,Leslie Lamport 的 Paxos 算法几乎已经成为一致性的代名词:Paxos 是在课程教学中最经常使用的算法,同时也是大多数一致性算法实现的起点 。Paxos 首先定义了一个能够达成单一决策一致的协议,比如单条的复制日志项 。我们把这一子集叫做单决策 Paxos 。然后通过组合多个 Paxos 协议的实例来促进一系列决策的达成 。Paxos 保证安全性和活性,同时也支持集群成员关系的变更 。Paxos 的正确性已经被证明,在通常情况下也很高效 。
不幸的是,Paxos 有两个明显的缺点 。第一个缺点是 Paxos 算法特别的难以理解 。完整的解释是出了名的不透明;通过极大的努力之后,也只有少数人成功理解了这个算法 。因此,有了几次用更简单的术语来解释 Paxos 的尝试 。尽管这些解释都只关注了单决策的子集问题,但依然很具有挑战性 。在 2012 年 NSDI 的会议中的一次调查显示,很少有人对 Paxos 算法感到满意,甚至在经验老道的研究者中也是如此 。我们自己也尝试去理解 Paxos;我们一直没能理解 Paxos 直到我们读了很多对 Paxos 的简化解释并且设计了我们自己的算法之后,这一过程花了近一年时间 。
我们假设 Paxos 的不透明性来自它选择单决策问题作为它的基础 。单决策 Paxos 是晦涩微妙的,它被划分成了两种没有简单直观解释和无法独立理解的情景 。因此,这导致了很难建立起直观的感受为什么单决策 Paxos 算法能够工作 。构成多决策 Paxos 增加了很多错综复杂的规则 。我们相信,在多决策上达成一致性的问题(一份日志而不是单一的日志记录)能够被分解成其他的方式并且更加直接和明显 。
Paxos算法的第二个问题就是它没有提供一个足够好的用来构建一个现实系统的基础 。一个原因是还没有一种被广泛认同的多决策问题的算法 。Lamport 的描述基本上都是关于单决策 Paxos 的;他简要描述了实施多决策 Paxos 的方法,但是缺乏很多细节 。当然也有很多具体化 Paxos 的尝试,但是他们都互相不一样,和 Paxos 的概述也不同 。例如 Chubby 这样的系统实现了一个类似于 Paxos 的算法,但是大多数的细节并没有被公开 。
而且,Paxos 算法的结构也不是十分易于构建实践的系统;单决策分解也会产生其他的结果 。例如,独立地选择一组日志条目然后合并成一个序列化的日志并没有带来太多的好处,仅仅增加了不少复杂性 。围绕着日志来设计一个系统是更加简单高效的;新日志条目以严格限制的顺序增添到日志中去 。另一个问题是,Paxos 使用了一种对等的点对点的方式作为它的核心(尽管它最终提议了一种弱领导人的方法来优化性能) 。在只有一个决策会被制定的简化世界中是很有意义的,但是很少有现实的系统使用这种方式 。如果有一系列的决策需要被制定,首先选择一个领导人,然后让他去协调所有的决议,会更加简单快速 。


推荐阅读