WARO协议
是一种简单的副本控制协议,当 Client 请求向某副本写数据时(更新数据),只有当所有的副本都更新成功之后,这次写操作才算成功,否则视为失败。这样的话,只需要读任何一个副本上的数据即可。但是WARO带来的影响是写服务的可用性较低,因为只要有一个副本更新失败,此次写操作就视为失败了。
从这里可以看出两点:①写操作很脆弱,因为只要有一个副本更新失败,此次写操作就视为失败了。②读操作很简单,因为,所有的副本更新成功,才视为更新成功,从而保证所有的副本一致。这样,只需要读任何一个副本上的数据即可。假设有N个副本,N-1个都宕机了,剩下的那个副本仍能提供读服务;但是只要有一个副本宕机了,写服务就不会成功。
Quorum机制
Quorum 的定义如下:假设有 N 个副本,更新操作 wi 在 W 个副本中更新成功之后,则认为此次更新操作 wi 成功,把这次成功提交的更新操作对应的数据叫做:“成功提交的数据”。对于读操作而言,至少需要读 R 个副本,其中,W+R>N ,即 W 和 R 有重叠,一般,W+R=N+1。
-
N = 存储数据副本的数量
-
W = 更新成功所需的副本
-
R = 一次数据对象读取要访问的副本的数量
听起来有些抽象,举个例子:
假设我有5个副本,更新操作成功写入了3个,另外2个副本仍是旧数据,此时在读取的时候,只要确保读取副本的数量大于2,那么肯定就会读到最新的数据。至于如何确定哪份数据是最新的,我们可以通过引入数据版本号的方式判断(Quorum 机制的使用需要配合一个获取最新成功提交的版本号的 metadata 服务,这样可以确定最新已经成功提交的版本号,然后从已经读到的数据中就可以确认最新写入的数据。)
Quorum一致性的局限性:
两个写操作同时发生,则无法明确先后顺序,这种情况下,唯一安全的解决方案是合并并发写入,然后根据时间戳或者版本号选取胜者,但这样也存在可能某些写入会被错误地抛弃。
如果有新值的节点后来发生失效,但恢复数据来自某个旧值,那么总的新值副本数会低于w,这就打破了之前的判定条件。
如果某些副本上已经写入成功,而其他一些副本写入失败,且总的成功副本数少于w,那么已成功的副本不会回滚,这意味着尽管这样写操作视为失败,后续的仍读操作可能返回新值。
宽松的quorum(sloppy quorum对于提高写入可用性特别有用,只要有w节点可用数据库就可以接受新写入,但这样的话满足w+r>n,也不能保证读取的时候读到最新值,因为新值可能被 临时写入n之外的某些节点且还没传过来)与数据回传
在一个大规模集群中(节点数远大于n),客户可能在网络中断期间还能连接到某些数据库节点,但是这些节点又不是能够满足数据仲裁(w+r>n)的那些节点:
这时候要么明确错误返回给客户端(因为不满足w+r>n)
或者使用(
接受该写请求,只是将它们暂时写入一些可访问的节点中,
注意这些节点并不在节点n个集合节点中
)
放松的仲裁:写入和读取仍然需要w和r个成功的相应,但是包含了那些并不在先前指定的n个节点。 等待网络之类问题解决,临时节点把需要接收到写入全部发送到原始主节点(这里是数据回传)比如你不小心把自己锁在了房子外面,然后就去领居家沙发休息下,然后自己家门开了再回自己家。