Riak 是以 Erlang 编写的一个高度可扩展的分布式数据存储,Riak的实现是基于Amazon的Dynamo论文,Riak的设计目标之一就是高可用。Riak支持多节点构建的系统,每次读写请求不需要集群内所有节点参与也能胜任。像这样的系统,我们需要版本机制来确定哪个值是最新的。所以就引入了向量时钟(Vector Clock)

当存储一个对象到Riak时,都被打上向量时钟标签。通过向量空间祖先继承的关系比较,Riak可以自动的修复不同步的值,使数据保持最终一致性。

向量时钟的作用

有个比较经典的例子,说明向量时钟的作用。假设有如下场景:

Alice、Ben、Catby和Dave四人约定下周一起聚餐,四个人通过邮件商量聚餐的时间。
Alice首先建议周三聚餐。
之后Dave和Catby商量觉得周四更合适。
后来Dave又和Ben商量之后觉得周二也行。
最后Alice要汇总大家的意见,得到的反馈如下:
Cathy说,他和Dave商量的时间是周四
Ben说,他和Dave商量的时间是周三 此时恰好联系不上Dave,而且不知道Cathy和Ben分别与Dave确定时间的先后顺序,Alice就不能确定到底该定在哪天了。

Vector Clock就是为了解决这种问题而设计的,简单来说,就是为每个商议结果加上一个时间戳,当结果改变时,更新时间戳。所以加上时间戳之后,我们再一次描述上面的场景,如下:

当Alice第一次提议将时间定为周三时,可以这样描述信息
date = Wednesday
vclock = Alice: 其他三个人都收到了信息,Dave和Ben开始交流,Ben建议改成周二,把Alice的初试向量加进去标识Ben看到Alice的消息了
date = Tuesday
vclock = Alice:, Ben: Dave回复Ben,确定周二可以
date = Tuesday
vclock = Alice:, Ben:, Dave: 然后Cathy开始说话,也和Dave说建议周四,此时在Dave看来就收到了两个数据如下:
date = Tuesday
vclock = Alice:, Ben:, Dave: date = Thursday
vclock = Alice:, Cathy:
这两份数据,各自都不是互相的祖先,所以就产生了冲突,Dave要自动解决这个冲突,他选择了周四,然后将消息改成如下,继承来自Dave现在收到的两条消息,这个消息发回给Cathy
date = Thursday
vclock = Alice:, Ben:, Cathy:, Dave: 最后来了,Alice只问Ben和Cathy最后的决定:
Ben说
date = Tuesday
vclock = Alice:, Ben:, Dave: Cathy说
date = Thursday
vclock = Alice:, Ben:, Cathy:, Dave: Alice就明白了,因为第二个Cathy说的是完全继承于Ben说的,所以最后采纳Cathy说的决定,周四去。

以上这个决策用到了向量时钟,有个图还比较清晰了说明整个过程:

向量时钟的空间无限增长问题

以上的做法还比较完美的解决了问题,这里只列举了四个决策者的向量时钟,不过在现实生活中,如果有很多的决策者,相当于有很多的客户端,整个向量时钟的长度就无限制增长了,这对于存储系统来说,不是一个好消息。我们需要想办法解决。

一个直接的想法是,不要用client来标识向量空间,用server来标识向量空间,因为server的数量是可控的,这里用X,Y两台server来重现以上决策的过程,只是标签不再用客户端,而是用server标识,决策过程如下

此时Dave收到两个消息

Tue X:2,Y:1  with Ben

Thu X:1,Y1   from Cathy (这个消息比较新)

发现后者是前者的祖先,所以自然抛弃祖先,最终最新的,这样就悄无声息的把Cathy给他的消息给丢了。

所以尝试用server来做标识,以期减少向量时钟的空间是不可取的,因为会丢数据。实际情况还是需要用客户端的标识来做向量时钟。

向量时钟的剪枝

所以为了解决向量时钟空间的无限增长问题,引入了向量时钟的剪枝

Riak用四个参数来避免向量时钟空间的无限增长:

  • small_vclock
  • big_vclock
  • young_vclock
  • old_vclock

small_vclock和big_vclock参数标识向量时钟的长度,如果长度小于small_vclock就不会被剪枝掉,如果长度大于big_vclock就会被剪枝掉

young_vclock和old_vclock参数标识存储这个向量时钟时的时间戳,剪枝策略同理,大于old_vclock的才会被剪枝掉,剪枝策略如下图

这样只会丢掉一些向量时钟的信息,即数据更新过程的信息,但是不会丢掉实实在在的数据。只有当一种情况会有问题,就是一个客户端保持了一个很久之前的向量时钟,然后继承于这个向量时钟提交了一个数据,此时就会有冲突,因为服务器这边已经没有这个很久之前的向量时钟信息了,已经被剪枝掉了可能,所以客户端提交的此次数据,在服务端无法找到一个祖先,此时就会创建一个sibling。

所以这个剪枝的策略是一个权衡tradeoff,一方面是无限增长的向量时钟的空间,另一方面是偶尔的会有"false merge",对,但肯定的是,不会悄无声息的丢数据。综上,为了防止向量时钟空间的无限增长,剪枝还是比用server标识向量时钟工作的更好。

参考:

http://docs.basho.com/riak/latest/theory/concepts/Vector-Clocks/

http://basho.com/why-vector-clocks-are-easy/

http://basho.com/why-vector-clocks-are-hard/

《大型网站系统与Java中间件实践》

向量时钟Vector Clock in Riak的更多相关文章

  1. Dynamo分布式系统——「RWN」协议解决多备份数据如何读写来保证数据一致性,而「向量时钟」来保证当读取到多个备份数据的时候,如何判断哪些数据是最新的这种情况

    转自:http://blog.jqian.net/post/dynamo.html Dynamo是Amazon开发的一款高可用的分布式KV系统,已经在Amazon商店的后端存储有很成熟的应用.它的特点 ...

  2. NoSQL生态系统——一致性RWN协议,向量时钟,gossip协议监测故障

    13.5 一致性 在NoSQL中,通常有两个层次的一致性:第一种是强一致性,既集群中的所有机器状态同步保持一致.第二种是最终一致性,既可以允许短暂的数据不一致,但数据最终会保持一致.我们先来讲一下,在 ...

  3. Vector Clock/Version Clock

    physical clock 机器上的物理时钟,不同的机器在同一个时间点取到的physical clock不一样,之间会存在一定的误差,NTP可以用来控制这个误差,同一个机房内的机器之间的时钟误差可以 ...

  4. Dynamo涉及的算法和协议——p2p架构,一致性hash容错+gossip协议获取集群状态+向量时钟同步数据

    转自:http://www.letiantian.me/2014-06-16-dynamo-algorithm-protocol/ Dynamo是Amazon的一个分布式的键值系统,P2P架构,没有主 ...

  5. Vector Clock理解

    背景近期在重读"Dynamo: Amazon's Highly Available Key-value Store"(经典好文,推荐!).文章4.4 中聊到了Data Versio ...

  6. 向量时钟算法简介——本质类似MVCC

    转自:http://blog.chinaunix.net/uid-27105712-id-5612512.html 一.使用背景 先说一下需要用到向量时钟的场景.我们在写数据时候,经常希望数据不要存储 ...

  7. R语言编程艺术# 数据类型向量(vector)

    R语言最基本的数据类型-向量(vector) 1.插入向量元素,同一向量中的所有的元素必须是相同的模式(数据类型),如整型.数值型(浮点数).字符型(字符串).逻辑型.复数型等.查看变量的类型可以用t ...

  8. 精解Mat类(一):基本数据类型-固定大小的 矩阵类(Matx) 向量类(Vector)

    一.基础数据类型 1.(基础)固定大小矩阵类 matx 说明: ①    基础矩阵是我个人增加的描述,相对于Mat矩阵类(存储图像信息的大矩阵)而言. ②    固定大小矩阵类必须在编译期间就知晓其维 ...

  9. R语言编程艺术#01#数据类型向量(vector)

    R语言最基本的数据类型-向量(vector) 1.插入向量元素,同一向量中的所有的元素必须是相同的模式(数据类型),如整型.数值型(浮点数).字符型(字符串).逻辑型.复数型等.查看变量的类型可以用t ...

随机推荐

  1. oracle默认配置ora文件位置

    unix:$ORACLE_HOME/dbsnt:c:\Oracle\ora81\database create spfile from pfile = '/home/oracle/initora11g ...

  2. file标签选择文件change事件失效处理方法

    file只能处罚一次change事件,在change事件中重新替换file标签即可生效 eg: $(function(){ //上传图片 $("body").on("ch ...

  3. android DisplayMetrics 获取屏幕分辨率

    Android 提供DisplayMetircs 类可以很方便的获取分辨率.下面介绍 DisplayMetics 类: Andorid.util 包下的DisplayMetrics 类提供了一种关于显 ...

  4. elk深度解析

    上面的两张图是elk的一个架构 下面是对logstash分析:如下图 可以看出 logstash的一个角色shipper,(是通过配置文件来决定logstash是shipper还是indexer)注意 ...

  5. 数据结构和算法 – 3.堆栈和队列

    1.栈的实现   后进先出     自己实现栈的代码 using System; using System.Collections.Generic; using System.Linq; using ...

  6. gcc【数学几何】

    GCC Time Limit: 1000MS Memory limit: 65536K 题目描述 The GNU Compiler Collection (usually shortened to G ...

  7. Linux环境下使用shell编写CGI(httpd)

    /var/www/cgi-bin/hello.sh #!/bin/bash echo "Content-type: text/html" echo "" ech ...

  8. 杂物 git rebase

  9. WPF ListView展示层叠信息

    通常我们在ListView中展示一列同类数据,例如城市名称.不过可以对ListView的DataTemplate稍作修改,让其显示层叠信息.例如:需要在ListView中显示省份和省份对应的城市名称. ...

  10. linux下java环境配置

    非常简单的三行命令就搞定了! $ sudo add-apt-repository ppa:webupd8team/java$ sudo apt-get update$ sudo apt-get ins ...