分布式系统中,一般保存多个数据副本,明显可以提高系统可靠性。并且存储这些数据副本的节点,不仅做容灾用,也可以提供服务,作负载均衡。
这里就涉及到一个数据一致性的问题,也就是各副本间要进行同步,来保持最新的数据。在一些一致性需求不辣么强的场景,比如用户获取某个文章的点赞数,读到未及时同步的脏数据也就无所谓了。
但在一些需要强一致性的场景里,这就比较可怕了。比如你银行卡里笼共就100块钱,第一次取了60元,第二次取的时候,请求路由到了未同步的那个副本数据上,你又可以取60元。银行就赔死了。
在这种需要强一致性的系统中,有一个简单的解决策略叫Read Only Write All。比如我分布式系统中有4个数据的副本,辣么当用户修改这个数据时,只有当系统中4个副本都同步为最新数据,才返回修改成功。这样读的时候,就一定是个好的数据了。
但在这种写操作频繁的系统,Write All对系统带来的负担就比较大了。
简单说就是,读很轻松,但写压力山大。那如何优化呢?Quorum算法就是一种方案。
算法的原理在wiki有介绍:
https://zh.wikipedia.org/wiki/Quorum_(%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F)#cite_note-1
wiki上写了它是基于鸽巢原理的。举个栗子:现在,我们有2绿2红4个球,分别放在不同的盒子里(鸽巢),那么,我们只要任意取3个球,就至少有一个绿球。道理很简单。
在我们的分布式系统中,可以把绿球看作新数据,红球看作未更新的脏数据。辣么!我们只要写了2份数据,也就是放了2个绿球,就可以返回写成功了。而这时候,想取出一个绿球(有效数据)就要费力一些了,至少要取3个球。
现在我们把4写一读,转换成了2写3读。这其实是对读写的一种负载均衡,用于减小写数据操作的压力。
当然,写2次读3次我们是肿么设计出来的呢。又要看wiki上Quorum算法原理了。简单来说,就是满足下面2个公式:
分布式系统中的每一份数据拷贝对象都被赋予一票。每一个操作必须要获得最小的读票数(Vr)或者最小的写票数(Vw)才能读或者写。如果一个系统有V票(意味着一个数据对象有V份冗余拷贝),那么这最小读写票必须满足:
1、Vr + Vw > V
2、Vw > V/2
第一条规则保证了一个数据不会被同时读写。当一个写操作请求过来的时候,它必须要获得Vw个冗余拷贝的许可。而剩下的数量是V-Vw 不够Vr,因此不能再有读请求过来了。同理,当读请求已经获得了Vr个冗余拷贝的许可时,写请求就无法获得许可了。
第二条规则保证了数据的串行化修改。一份数据的冗余拷贝不可能同时被两个写请求修改。
我们惊奇的发现,上面设计的2写3读,并不符合以上第二条规则。也就是只保证一个数据不被同时读写,但仍不能保证这个数据不被两个请求同时写。。。
3写2读就可以解决了。
原文地址:https://www.cnblogs.com/gm-201705/p/9863910.html