Riak VClock

关于向量时钟的概念。在这里就多讲了,大家能够參照一下Dynamo的论文了解一下,向量时钟在分布式主要用于解决一致性性问题。能够和CRDTs一起看。

以下的源码是參照riak中的,就是把它翻译为elixir格式而已。基本不变。

时钟主要出现的情况有网络分区和并行更新。

这样仅仅会丢掉一些向量时钟的信息,即数据更新过程的信息,可是不会丢掉实实在在的数据。仅仅有当一种情况会有问题,就是一个client保持了一个非常久之前的向量时钟,然后继承于这个向量时钟提交了一个数据,此时就会有冲突。由于服务器这边已经没有这个非常久之前的向量时钟信息了,已经被剪枝掉了可能,所以client提交的此次数据,在服务端无法找到一个祖先。此时就会创建一个sibling。所以这个剪枝的策略是一个权衡tradeoff,一方面是无限增长的向量时钟的空间。还有一方面是偶尔的会有"false merge"。对,但肯定的是,不会悄无声息的丢数据。综上。为了防止向量时钟空间的无限增长,剪枝还是比用server标识向量时钟工作的更好。

  • 结构:

主要有3个元祖{node, {opCount, TS}},分布为节点(协调器)。操作数和操作时间。

  • 基本的方法:

merge(合并):

合并的规则是,opCount>TS:当节同样时,谁的opCount大,谁赢;假设opCount一样时,谁的时间大谁赢。

@doc """Combine all VClock in the input list into their least possible common descendant"""@spec merge(list, list) :: listdef merge([]), do: []def merge([singevclock]), do: singevclock## first is a list, eg [:a, {1, 1234}]# rest is list of list, eg [[{:a, {1, 233}}, {:b, {3, 124}}]]def merge([first|rest])  domerge(rest, :lists.keysort(1, first))enddef merge([], nclock), do: nclockdef merge([aclock|vclocks], nclock)  domerge(vclocks, merge(:lists.keysort(1, aclock), nclock, []))enddef merge([], [], accclock), do: :lists.reverse(accclock)def merge([], left, accclock), do: :lists.reverse(accclock, left)def merge(left, [], accclock), do: :lists.reverse(accclock, left)def merge(v = [{node1, {ctr1, ts1} = ct1} = nct1 | vclock],n = [{node2, {ctr2, ts2} = ct2} = nct2 | nclock], accclock) docond donode1 < node2 ->merge(vclock, n, [nct1|accclock]);node1 > node2 ->merge(v, nclock, [nct2|accclock]);true ->({_ctr, _ts} = ct) = cond doctr1 > ctr2 ->ct1;ctr1 < ctr2 ->ct2;true ->{ctr1, :erlang.max(ts1, ts2)}endmerge(vclock, nclock, [{node1, ct}|accclock])endend

prune(裁剪):

裁剪的法则主要是空间时间双方面.
!()[../pic/riak_4.png]

终于的裁剪函数prune_vclock1(v, now, bprops, headtime).

@doc """Possibly shrink the size of a vclock, depending on current age and size"""@spec prune(v :: list, now :: integer, bucketprops :: any) :: listdef prune(v, now, bucketprops) do## This sort need to be deterministic, to avoid spurious merge conflicts later,# We achieve this by using the node ID as secondary keysortv = :lists.sort(fn({n1, {_, t1}}, {n2, {_, t2}}) -> {t1, n1} < {t2, n2} end, v)prune_vclock1(sortv, now, bucketprops)enddef prune_vclock1(v, now, bprops) docase get_property(:small_vclock, bprops) >= :erlang.length(v) dotrue -> v;false ->{_, {_, headtime}} = hd(v)case (now - headtime) < get_property(:young_vclock, bprops) dotrue -> v;false -> prune_vclock1(v, now, bprops, headtime)endendenddef prune_vclock1(v, now, bprops, headtime) do# has a precondition that v is longer than small and older than youngcase (:erlang.length(v) > get_property(:big_vclock, bprops)) or ((now - headtime) > get_property(:old_vclock, bprops)) dotrue -> prune_vclock1(tl(v), now, bprops);false -> vendenddef get_property(key, pairlist) docase :lists.keyfind(key, 1, pairlist) do{_key, value} ->value;false ->:undefinedendend
  • source
defmodule VClock do@moduledoc """this is !!!!!!!!"""@vsn 0.1@spec fresh() :: []def fresh do[]end# return true if va is a direct descendant of vb, else false -- remember, a vclock is its own descendant!@spec descends(any, []) :: (true|false)def descends(_, []) dotrueend@type va :: list()@spec descends(any, any) :: (false|true)def descends(va, vb) do[{nodeb, {ctrb, _}} | resetb] = vbcase :lists.keyfind(nodeb, 1, va) dofalse ->false;{_, {ctra, _tsa}} ->(ctra >= ctrb) && descends(va, resetb)endend@doc """Combine all VClock in the input list into their least possible common descendant"""@spec merge(list, list) :: listdef merge([]), do: []def merge([singevclock]), do: singevclock## first is a list, eg [:a, {1, 1234}]# rest is list of list, eg [[{:a, {1, 233}}, {:b, {3, 124}}]]def merge([first|rest])  domerge(rest, :lists.keysort(1, first))enddef merge([], nclock), do: nclockdef merge([aclock|vclocks], nclock)  domerge(vclocks, merge(:lists.keysort(1, aclock), nclock, []))enddef merge([], [], accclock), do: :lists.reverse(accclock)def merge([], left, accclock), do: :lists.reverse(accclock, left)def merge(left, [], accclock), do: :lists.reverse(accclock, left)def merge(v = [{node1, {ctr1, ts1} = ct1} = nct1 | vclock],n = [{node2, {ctr2, ts2} = ct2} = nct2 | nclock], accclock) docond donode1 < node2 ->merge(vclock, n, [nct1|accclock]);node1 > node2 ->merge(v, nclock, [nct2|accclock]);true ->({_ctr, _ts} = ct) = cond doctr1 > ctr2 ->ct1;ctr1 < ctr2 ->ct2;true ->{ctr1, :erlang.max(ts1, ts2)}endmerge(vclock, nclock, [{node1, ct}|accclock])endend@doc """get the counter value in vclock set from node"""@spec get_counter(node :: atom, vclock::list) :: (integer|:undefined)def get_counter(node, vclock) docase :lists.keytake(node, 1, vclock) do{_, {c, _}} -> c;false -> :undefinedendend@doc """Get the timestamp value in a VClock set from node"""@spec get_timestamp(node :: atom, vclock :: list) :: (integer | :undefined)def get_timestamp(node, vclock) docase :lists.keytake(node, 1, vclock) do{_, {_, ts}} -> ts;false -> :undefinedendend@doc """increment VClock at node"""@spec increment(atom, list) :: integerdef increment(node, vclock) doincrement(node, timestamp(), vclock)end@spec increment(atom, integer, list) :: listdef increment(node, incts, vclock) doIO.puts "#{inspect node}, #{inspect incts}, #{inspect vclock}"{{_ctr, _ts} = c1, newv} = case :lists.keytake(node, 1, vclock) dofalse ->{{1, incts}, vclock};{:value, {_n, {c, _t}}, modv} ->{{c + 1, incts}, modv}end[{node, c1} | newv]end# retrun the list of all nodes that have ever incremented VClock@spec all_nodes(vclock :: list) :: (list)def all_nodes(vclock) dovclock |> Enum.map(fn({x, {_, _}}) -> x end)end@days_from_gergorian_base_to_epoch (1978 * 365 + 478)@seconds_from_gergorian_base_to_epoch (@days_from_gergorian_base_to_epoch * 24 * 60 * 60)@spec timestamp() :: integerdef timestamp do{megaseconds, seconds, _} = :os.timestamp()@days_from_gergorian_base_to_epoch + megaseconds * 1000000 + secondsend@doc """Compares two VClock for equality"""@spec equal(va :: list, vb :: list) :: (true | false)def equal(va, vb) doEnum.sort(va) === Enum.sort(vb)end@doc """Possibly shrink the size of a vclock, depending on current age and size"""@spec prune(v :: list, now :: integer, bucketprops :: any) :: listdef prune(v, now, bucketprops) do## This sort need to be deterministic, to avoid spurious merge conflicts later,# We achieve this by using the node ID as secondary keysortv = :lists.sort(fn({n1, {_, t1}}, {n2, {_, t2}}) -> {t1, n1} < {t2, n2} end, v)prune_vclock1(sortv, now, bucketprops)enddef prune_vclock1(v, now, bprops) docase get_property(:small_vclock, bprops) >= :erlang.length(v) dotrue -> v;false ->{_, {_, headtime}} = hd(v)case (now - headtime) < get_property(:young_vclock, bprops) dotrue -> v;false -> prune_vclock1(v, now, bprops, headtime)endendenddef prune_vclock1(v, now, bprops, headtime) do# has a precondition that v is longer than small and older than youngcase (:erlang.length(v) > get_property(:big_vclock, bprops)) or ((now - headtime) > get_property(:old_vclock, bprops)) dotrue -> prune_vclock1(tl(v), now, bprops);false -> vendenddef get_property(key, pairlist) docase :lists.keyfind(key, 1, pairlist) do{_key, value} ->value;false ->:undefinedendendend
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5229840.html,如需转载请自行联系原作者

Riak VClock相关推荐

  1. 向量时钟Vector Clock in Riak

    Riak 是以 Erlang 编写的一个高度可扩展的分布式数据存储,Riak的实现是基于Amazon的Dynamo论文,Riak的设计目标之一就是高可用.Riak支持多节点构建的系统,每次读写请求不需 ...

  2. Riak的一个PHP扩展

    安装 git submodule init git submodule update phpize ./configure sudo make install extension=riak.so -- ...

  3. Riak Core Guide 3

    Learn Riak Core Step By Step 3 Riak Core, Conflict Resolution 这一章主要描述最终一致性和如何实现强一致性. Object 非重重要的一个数 ...

  4. An eventually consistent data model for Erlang (and Riak)

    CAP理论指出:一个分布式系统不可能同时满足一致性(Consistency).可用性(Availibility)和分区容忍性(Partition Tolerance)这三个需求,最多只能同时满足其中的 ...

  5. IOT数据库选型——NOSQL,MemSQL,cassandra,Riak或者OpenTSDB,InfluxDB

    补充: Basho公司开源了它的时序数据库产品Riak TS 1.3 代码在github riak的riak-ts分支上! Riak KV产品构建于Riak内核之上,提供了一种高弹性.高可用的键值数据 ...

  6. 分布式系统中一些主要的副本更新策略——Dynamo/Cassandra/Riak同时采取了主从式更新的同步+异步类型,以及任意节点更新的策略。...

    分布式系统中一些主要的副本更新策略. 1.同时更新 类型A:没有任何协议,可能出现多个节点执行顺序交叉导致数据不一致情况. 类型B:通过一致性协议唯一确定不同更新操作的执行顺序,从而保证数据一致性 2 ...

  7. riak文件服务器,Docker中运行Riak服务 - Docker 中文指南

    这个例子的目的是向您展示如何构建一个预装Riak的docker镜象. 创建Dockerfile 创建一个空文件Dockerfile $ touch Dockerfile 接下来,定义你想要来建立你镜像 ...

  8. [zz]NoSQL对比:Cassandra vs MongoDB vs CouchDB vs Redis vs Riak vs HBase vs Membase vs Neo4j

    原文自:http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis Cassandra vs MongoDB vs CouchDB vs Re ...

  9. riak php7,Laravel中服务提供者的register和boot分别是干什么

    register方法 正如前面所提到的,在register方法中只绑定事物到服务容器,而不要做其他事情,否则,一不小心就能用到一个尚未被加载的服务提供者提供的服务. 现在让我们来看看一个基本的服务提供 ...

最新文章

  1. 【剑指Offer】16重建二叉树
  2. 修改docker镜像的存储地址的方法(--graph)
  3. PHP权重算法-用于游戏根据权限来随机物品
  4. P3112-[USACO14DEC]后卫马克Guard Mark【贪心】
  5. Android进阶——Crash异常捕获并发送到服务器
  6. 知了课堂项目part1
  7. 2021年中职“网络安全“江西省赛题—B-8:Web渗透测试
  8. 语音识别算法原理文档整理(一)
  9. C语言程序设计专项练习——PTA
  10. 解决联想电脑插入耳机没有声音问题
  11. 计算机网络原理 读书笔记
  12. 固态硬盘是什么接口_笔记本固态硬盘的接口有哪些?来学习下笔记本SSD小知识...
  13. pandas处理excel单元格合并后的列
  14. cdr轮廓字怎么把轮廓拆出来_用corelDraw怎么把文字做成轮廓?
  15. 入门阿里云Dataphin(1)
  16. IEC61850开发流程
  17. CocosCreator H5小游戏屏幕适配解决方案
  18. 计算机软件统考,计算机统考_计算机与软件_考研论坛(kaoyan.com)
  19. 树莓派打造成全能路由器
  20. mysql sp_helptext_数据库sp_helptext

热门文章

  1. python中的format什么意思中文-Python中format的用法
  2. arcgis python编程案例-面向ArcGIS的Python脚本编程
  3. python编程工具p-python Gui开发工具选择
  4. python编程基础教程-史上最全Python编程基础入门教程
  5. python输出数据到excel-python实现数据导出到excel的示例--普通格式
  6. shell脚本中的命令替换
  7. talib 中文文档(八): Momentum Indicator Functions 动量指标
  8. 证书重复冲突问题:Command /usr/bin/codesign failed with exit code 1
  9. js及jQuery实现checkbox的全选、反选和全不选
  10. Android开发学习之路-让注解帮你简化代码,彻底抛弃findViewById