故事的开始
如果从 Lamport 的 basic paxos算法开始捡起来还是有点复杂。我建议从单机开始讲起,对产品不停地迭代。
最简单的场景
假如,现在我们有一套5个人,需要修改一个变量的值,那就存在竞争问题了。
每个人修改值都会做3件事情,那就是读\计算\写。
那么就存在一个问题,如果5个人同时对这个变量读写该以谁为准呢?。
(我们为了不复杂化我们的系统设计,所以第一个版本,我们【把变量寄放在一块共享内存】)
第一个游戏规则
如果5个人同时对这个变量读写该以谁为准呢?
为了简单粗暴,我们会以最大的为准(像比特币的话,就是以区块链最长的为准,我们这里没有女巫攻击,所以可以简单粗暴点)。
第一个并发修改值的问题得到了解决。
特点:这样做出来的集群,具备了读写一致性,以及实时有效性。也就说无论什么时候,客户端都能读取到有效值,而且服务器某一瞬间分发给客户端的值,永远都是一样的。
缺点:
- 共享内存是单机的,不具备高可用。
- 共享变量无法正常update,只能单调递增,不服合正常业务场景。
版本号的出现
- 为了能够支持正常的业务update,我们决定用变量的高64位座位版本ID,真正的数值放在低32位。这样就可以继续“以最大数为准”,而且又不影响我们读写业务数据。mysql和zk的事务都是这样做的(包括比特币也是)。
分区的出现
为了高可用,我们把数据存放在多个节点。这就意味着,每次提交写事务,都得到所有节点进行同步,这个过程我们称之为【广播消息】
从设计来看,我们实现了分布式存储,我们的数据在每一个存储节点都有一个副本。这就是所谓的分区。(复杂的分区都是跨地域机房的)
处理CAP原理
根据CAP原理,我们既然选择了对存储分区,那么Consistency(一致性)、 Availability(可用性)只能二选一了。
我们先说说分区会出现什么问题:
分区会出现节点之间数据不一致,虽然说大部分情况下数据是一致的。当万一出现网络故障,或者网络联通出现隔离分区等情况,数据很容易就不一致了。这个时候我们得出方案确保数据重新变成一致。
比如我们经常说的“脑裂现象”。
解决方案:
由于我们没有中心指挥官,所以只能让所有节点各自约定,以过半数的值为准,比如说我作为集群中的一个副本,每次收到一个新版本的数据,我都会向集群的其他节点发起询问,如果超过一半的节点都用了新版本数据,那么自己也用新版本数据,否则用继续保持旧版本。
有了这样原则,我们集群不可能存在脑裂现象,因为集群在任何一个瞬间都只能有一个事务版本号超过半数(我们的集群是基数个的前提下)。
到这里我们已经解决了所有问题。
那么我们的basic-paxos算法诞生了。
进阶的mutil-paxos算法
由于basic-paxos算法每次写数据都要选举特别麻烦,因为他没有leader。
而mutil-paxos则利用basic-paxos选出Leader,在有leader的情况下写数据就不走麻烦的basic-paxos算法过程了,而是让所有节点以leader节点为准,这等于不需要考虑分区问题了。大大提高了集群写数据的性能。
ZAB协议则是对mutil-paxos算法的一种实现
看了很多资料都会讨论各种场景下zab协议的运行细节,其实大可不必去记忆,因为重要的我们要站在集群中存储节点的角度去考虑将要面对的问题,以及每种问题的解决方案即可,而上面列出的已经是全部问题与解决方案了。