1. 分布式系统为什么需要Quorum算法?——WARO机制

分布式系统就是利用多台计算机协同解决单台计算机无法解决的计算、存储等问题 , 但由于在系统运行过程中,因为节点基数大的缘故,网络异常、节点宕机等异常情况的发生几乎是肯定的。

为了保证系统的正常运行 , 提供可靠的服务 , 分布式系统对于数据的存储采用了多份数据副本(副本不仅可以用于备份 , 还可以参与提供服务) 来保证可靠性。也就是说 , 如果请求数据的时候 , 有一个节点读取数据失败了,那么可以将请求转向另一个存有相同数据副本的结点。这个过程对于用户来说是透明的。

但是随之而来的一个问题 : 怎么样保证每个节点存储的数据是一致的?因为,如果用户提交了一次修改,那么原先保存的副本显然就与当前数据不一致了。

解决这个问题最简单的方法是 : WARO(Write All Read Only)机制。WARO是一种简单的副本控制协议 , 当Client请求向某副本更新数据时 , 只有当所有的副本都更新成功之后 , 这次写操作才算成功 , 否则视为失败。也就是说 , 在用户更新数据之后 , 系统确保更新数据在所有的副本都更新完之后 , 再告诉用户操作成功;而用户在读取数据的时候 , 系统只需要查询其中一个副本数据就可以返回给用户了。

但是WARO机制在经常需要更新数据的系统中就不太友好了 , 写操作时延现象会非常明显 , 如果再加上并发或者连续执行的情况, 那效率可想而知了。

假设有N个副本 , N-1个节点都宕机了 , 剩下的那一个副本依然能提供读服务 ; 但只要有一个副本宕机了 , 写服务就不会成功。

从这里我们可以看到 , 写服务和读服务承受的压力不均衡, 即负载不均衡。

所以我们需要一种方案 , 可以在不需要更新全部数据的情况下 , 还能保证返回给用户的是有效数据的解决方案。Quorum算法便是一种选择

2. 鸽巢原理是怎么应用到Quorum算法中?

鸽巢原理 , 就是如果有n个笼子和n+1只鸽子 , 所有的鸽子都被关进笼子里 , 那么至少有一个笼子有至少2只鸽子。我们将其变形一下 , 如果有两个笼子 , 一个笼子放了两只灰鸽子 , 另一个笼子放了两只白鸽子 , 如果我们取出三只鸽子 , 无论怎么取至少会有一只灰鸽子。

类比一下 , 我们把灰鸽子看成是已经更新的有效数据 , 把白鸽子看成是未更新的无效数据 , 那么我们不需要更新所有数据(并非全部是灰鸽子),我们就可以得到有效数据,当然,我们需要读取多个副本才能完成(取出多只鸽子)。

这就是Quorum机制的原型,也就是把写服务的负载压力均衡到读服务上了。

3. 什么是Quorum算法?

Quorum算法指的是: 分布式系统中的每一份数据拷贝对象都被赋予一票。每一个读操作获得的票数必须大于最小读票数(read quorum)(Vr) , 每个写操作获得的票数必须大于最小写票数(write quorum)(Vw)才能读或者写。如果系统有V票(意味着一个数据对象有V份冗余拷贝) ,那么最小读写票数(quorum)应满足如下限制:

Vr + Vw > V
Vw > V/2

第一条规则保证了一个数据不会被同时读写。当一个写操作请求过来的时候, 它必须要获得Vw个冗余拷贝的许可。而剩下的数量是V-Vw 不够Vr , 因此不能再有读请求过来了。同理 , 当读请求已经获得了Vr个冗余拷贝的许可时 , 写请求就无法获得许可了。

第二条规则保证了数据的串行化修改。一份数据的冗余拷贝不可能同时被两个写请求修改。

简单说 , 假设有N个副本。当更新操作w在超过Vw个副本上成功之后,才认为此次更新操作成功;而对于读操作而言,至少需要读到Vr个副本才能读到此次更新的数据。其中Vw+Vr>N , 即Vw和Vr有重叠 , 一般Vr + Vw = N + 1。

quorum

举个栗子 , 假设系统有5个副本 , Vw=3 , Vr=3。初始时数据为(V1,V1,V1, V1,V1)——【成功提交的版本号为1】。

在某次更新操作在3个副本上成功之后 , 就认为此次更新操作成功。数据变成 :( V2, V2, V2, V1, V1)——【成功提交的版本号为2】

因此 , 最多只需要读3个副本 , 一定就可以读到V2(此次更新成功的数据)。而后台可以对剩余的V1同步成V2,且不需要让Client知道。

4. 怎么运用Quorum算法解决WARO机制的负载均衡问题?

回到文章开头,我们看看怎么运用Quorum算法解决WARO机制的负载均衡问题。

其实关键在于 , 更新了多少个数据副本之后 , 可以使得读取时总能读到有效数据?

假使总共有N个数据副本 , 其中k个已经更新 , N-k个未更新副本 ,那么我们任意读取N-k+1个数据副本时必然至少有1个是已经更新的副本, 也就是Quorum的交集。我们只需要比较读取的N-k+1个副本中版本最高的那个数据返回给用户 , 那就是最新更新的数据。

而对于写模型来说 , 只要系统完成k个副本的更新后 , 就可以告诉用户操作完成而不需要所有副本都完成更新 , 当然 , 系统内部还是会慢慢把剩余副本都更新了 , 这对于用户来说 , 是透明的。

可以看到 , 我们把写操作的部分负载转移到了读操作上 , 读操作读取多个数据副本 , 使得写操作负载不会太重。但这也弱化了分布式系统中的数据一致性,实现的是最终一致性。

5. 运用了Quorum算法的系统架构简图是怎么样的?

假设quorum值 = (系统节点数/2)+1 , B系统必须部署奇数台节点 , A系统每次向B系统发送数据 , 都必须给B系统中的每个节点发送一次。A系统判断本次数据发送成功与否的依据是 , 在指定时间内 , B系统中至少有quorum台节点回复了ACK , 即B系统中超过半数的节点接收成功。


引用链接

分布式系统理论 : Quorum算法NYfor2020的博客-CSDN博客quorum算法


熊熊