分布式高可用键值对数据库Riak - 背景篇(3)
Dynamo对于数据版本的处理
数据版本问题不止存在于分布式系统,这里针对分布式数据库系统简单讨论下。先看一个简单的例子,用户x对key1做了一次写入操作,我们设值是数字3。然后用户y读取了key1,这个时候用户y知道的值是3。然后用户x对值做了一个+1操作,将新值写入,现在key1的值是4了。而用户y也做了一次+1操作,然后写入,因为用户y读到的值是3,y不知道这个值现在已经变化了,结果按照语义本应该是5的值,现在还是4。
解决这个问题常用的方法是设置一个版本值。用户x第一次写入key1 值3的时候,产生一个版本设为v1。用户y读取的信息中包括版本编号v1。当x做了加1把值4写入的时候,告诉server自己拿到的是版本v1,要在v1的基础上把值改成4。server发现自己保存的版本的确是v1所以就同意这个写入,并且把版本改成v2。这个时候y也要写入4,并且宣称自己是在版本v1上做的修改。但是因为server发现自己手里已经是版本v2了,所以server就拒绝y的写入请求,告诉y,版本错误。这个算法在版本冲突的时候经常被使用。
但是对于如我们刚才描述的分布式数据库系统,就不能这么做。假设我们设置了N=3 W=1。现在x写入key1 值3,这个请求被节点A处理,生成了v1版本的数据。然后x用户又在版本v1上进行了一次key1值4的写操作,这个请求这次是节点C处理的。但是节点C还没有收到上一个A接收的版本(数据备份是异步进行的)如果按照上面的算法,他应该拒绝这个请求,因为他不了解版本v1的信息。但是实际上是不可以拒绝的,因为如果C拒绝了写请求,实际上W=1这个配置,这个服务器向客户做出的承诺将被打破,从而使得系统的行为退化成W=N的形式。那么C接收了这个请求,就可能产生前面提到的不一致性。如何解决这个问题呢?
Dynamo 的方法是保留所有这些版本,用vector clock记录版本信息。当读取操作发生的时候返回多个版本,由客户端的业务层来解决这个冲突合并各个版本。当然客户端也可以选择最简单的策略,就是最近一次的写覆盖以前的写。
举个例子:
假设处理运单一,一开始请求发送到了E机器,更新status为1。E对应的虚节点上会记录E1((status:1,E)),并同步给其他备份节点。
之后请求又发送到了E机器,更新status为2。E对应的虚节点上会更新记录E2((status:2,E)),并同步给其他备份节点。
假设这时 ,有更新请求到了B和A上,B和A会分别更新自己的记录为B1(((status:2,E),(status:3,B))和A1(((status:2,E),(status:4,A))
之后,经过同步,每个虚节点会保存冲突版本,直到业务端解决冲突
啰嗦下NoSQL与数据库趋势
首先还是存在了20多年的关系型数据库,它还是很成功的,能够稳定的运行在单机环境并可靠的持久化数据,并能控制并发访问有效的处理事务。
但是这种基于关系代数创造出来的关系型数据库,与研发人员设计的实体对象类,并不是很匹配。于是出现了一些类似于Hibernate和MyBatis这样的ORM(对象关系映射)层框架产品。
传统上,应用的各个模块都把同一份数据库当做共用的集成点。但是现在,流行的应用设计思想比如说微服务的思想可以理解为每个应用模块都会封装自己的数据库,并通过服务彼此集成。集群化的思想也日趋流行,但是,传统的关系型数据库在集群上的表现很差。这也是CAP理论的验证,因为传统的关系型数据库,一致性(C)和可用性(A)保证得很好,但是分区集群容错性(P)表现的就不那么好了。
于是,强调不同CAP维度的NoSQL出现了。
Riak简介
Riak是Basho公司推广开发的基于Amazon的Dynamo理论的键值对分布式数据库。Basho Technologies,分布式NoSQL数据库Riak的创建者,在经历一轮强劲的增长之后获得了2500万美元的G轮融资,这些资金正被用来扩大开发和营销活动。Riak是开源的,但是Basho的Riak Enterprise增加了multi-data center复制等主要功能,这项特性使得在全球范围内分布式工作负载、监控和不间断支持成为可能。
我们可以把Riak理解为之前我们所述Dynamo理论的一个不错的实现。
Riak到现在主要经历了两个时代,分别是1.0和2.0时代。
Riak主要有如下几个重要特性:
- 键值型数据库,所有键值对放在不同的桶(bucket)中。
- 基于NWR模型的高可用,Riak可以通过读写多个服务器来保证网络断掉或者机器宕机时维持服务可用。
- 集群增加新的节点时,不用很繁琐的操作,可以实现便捷扩容
- Riak可以将数据均匀的分布到集群内的每一个节点上,从而保证性能近似线性地随着机器增加而增加。
- Riak是无主集群,在集群中某一节点宕机或者永久性损坏不会影响整个集群
- 版本向量解决分布是数据冲突。就是本文开头说的冲突解决办法
- Map-reduce操作
在2.0以后,引入了如下更多的特性:
- 新的CRDT(Conflict-free Replicated Data Type)数据类型。但是需要Bucket显示指定特定的数据类型
- 强一致性改进,Riak安全相关,新型Riak搜索引擎(集成Solr) - 这些需要Riak配置文件显式地打开。
- Dotted Version Vectors (DVVs) 新型的版本向量方案