关于分布式系统共识的思考

分布式系统的挑战

在前面的文章里,我们分析了分布式系统在业务上的一致性技术,即分布式事务,它的结果导向是面向用户的。然而在我们的系统内部,有时也需要面对来自软件架构等更高层次上的一致性要求,比如 Redis 的哨兵模式,Zookeeper 的选举过程等。它们所考虑的一致性更多的是服务节点之间一个共识的达成,当共识达成之后,就可以以此为指导原则,展开更多的协同操作。

在研究怎么达成共识之前,我们先来分析下分布式系统的特性:

  • 并发: 不同节点上的进程是能够同时执行的,我们需要协调机制去完成各个阶段任务。
  • 全局时钟: 在分布式系统里,基本很难去维护一个全局时钟,各个服务器在时间顺序上是没有绝对的。
  • 故障影响: 不存在没有故障的系统,需要考虑对系统的整体影响,以及系统所能提供的容错处理能力。
  • 消息传递:由于网络的复杂环境,节点与节点之间的通信有可能到达,也可能部分到达,可能在已知的时间范围内传送,也可能无限期延迟,这都是不一定的。

由此可见,关于在一个分布式系统里想达成共识的挑战在于协调容错非确定通信

状态复制

如果说我们想在一个系统中引入协调者的话,那么非常简单,引入一个有状态的组件即可,通过状态的判断来保证当前系统应该处于哪个业务阶段。一个有状态的组件是很好实现的,只要带持久化功能即可,像 Mysql,MongoDB。不过,考虑到协调者的重要性,我们往往是需要保证它高可用性的,为了达到这一目的,我们会在状态的更新过程中加入复制流程。比如将更新后的值,同步给其他机器。

但是,是否需要所有的机器都复制到位了,才能完成此次的更新流程?不一定,像 Mysql 同步复制、异步复制、半同步复制就是在性能与数据一致性上给我们提供了多种选择,只是复制的执行效率越高,数据一致性就越低。

像我们这种协调者更新频率低,数据量小,则往往会采用少数服从多数的策略,只要同步节点超过了一半,那么就可以认为此次写入成功了。Raft 的日志同步,Zookeeper 的消息广播就是这么处理的。除此之外,为了保证同步的正确性,还会引入选举机制,让选举出来的 Leader 节点统一处理同步结果。当 Leader 节点故障或下线时,将会根据一定的规则进行重新选举 (比如日志的最新提交程度),保证系统的正常运行。

故障处理

在上面达成共识的方法里,势必要考虑故障的影响,而对应的故障类型主要有两种:

  • 崩溃故障:节点突然崩溃并停止对其他节点的响应
  • 拜占庭失败:节点是不可信任的,将会响应错误的消息给其他节点

针对于崩溃故障这种类型的失败,我们可以像 Raft, Paxos 协议一样,通过选举来解决。但是像拜占庭失败这种问题就比较难解决了,由于有可能存在叛变的节点,使得整个系统往错误的方向去达成共识,显而易见,这不是我们想要的。所以我们会在区块链里看到如下的解决算法:

  • PBFT(Practical Byzantine Fault Tolerance):拜占庭容错算法 (联盟链/私有链使用此算法)
  • PoW(Proof of Work):工作量证明算法 (比特币和以太坊使用此算法)

FLP 不可能原理

关于分布式系统之间的通信模型,总体上可以划分下面这两种类型:

  • 同步:系统处理消息的时间是在规定范围内的,一旦超出,则直接认为失败。
  • 异步:系统处理消息的时间是不定的,有可能获取到结果,也可能一直获取不到了。

其中,在异步通信模型下,有一个著名的 FLP不可能原理,即:

在网络可靠、但允许节点失效(即便只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性共识算法

FLP 不可能原理告诉我们,不要浪费时间为异步分布式系统设计任意场景的共识算法。我们应该将精力放在一个有约束、有终止条件的分布式系统中,如果我们设计的算法尽可能的满足以下两个条件,那么我们的系统将将会有共识的输出:

  • 活性:每个非故障节点最终将会决定输出某个值,如果节点不做决定,那么系统就会停止。
  • 安全:所有非故障节点最终将会输出相同的值,如果达不到该效果,那么一致性很难保证。

共识的达成

不同的算法对上面的条件描述会不一样,从广义上来讲,共识算法通常会进行以下三种角色的划分:

  • 提议者:通常被称为领导者或协调者
  • 接受者:响应提议者提出的议案
  • 学习者:不参与决策,学习决定的最终值

当角色职责划分好后,我们会通过以下三个步骤来定义一个共识算法:

第 1 步 选举: 当有外部事件触发时,由领导者提出下一个有效的输出值。
第 2 步 投票: 非故障节点接收到领导者提议的值后,对其验证,并将其提议为下一个有效值。
第 3 步 决定: 根据有效值在各个非故障节点的提议结果,决定是否采用该值;否则重新开始步骤 1

对于以上的步骤,不同的共识算法会有一些差异,比如术语定义、投票处理流程、有效值的决定标准等。

应用

分布式系统共识的达成需要在不可靠、不可信的网络里完成。如果不进行所谓的拜占庭容错,那么我们的 raft、zookeeper 协议就足够了,而它们的应用场景往往也是在内网之中,所以默认内部节点都是可信的。如果我们要在包含恶意行为的开放的网络群体里达成共识,例如区块链,那么我们就不得不解决考虑以下三种情况的完善了:

  • 合理化:参与者根据利益最大化的策略去选择协议的执行。
  • 利它式:执行的过程中,能考虑整体的利益。
  • 拜占庭式容错:能抵抗某些节点恶意的行为,保证系统正常运行。

总结

分布式系统达成共识的过程需要有活性安全的保障,其协商一致机制也需要将拜占庭错误考虑进去。共识问题的解决让我们的分布式系统运行的更加健壮,也正是因为共识的重要性,当今区块链技术才显得额外的重要!

参考


感兴趣的朋友可以搜一搜公众号「 阅新技术 」,关注更多的推送文章。
可以的话,就顺便点个赞、留个言、分享下,感谢各位支持!
阅新技术,阅读更多的新知识。
阅新技术

你可能感兴趣的