传统数据库系统是具备ACID属性的,’D’代表持久性,NoSQL系统通常都是通过他们内存模型来描述的,比如:强一致性和最终一致性。我们可以看到,Durability不是一个可以被轻易忽略的特性。
最终一致性的定义
最终一致性比较公认的定义是由Werner Vogels发表的:
"the storage system guarantees that if no new updates are made to the object, eventually all accesses will return the last updated value. 存储系统可以保证:对于同一个数据对象,如果没有更多的更新产生,最终所有的访问都会返回最新更新的数据(版本)。”
也还有一些其他的定义,例如Baillis和Ghodsi是这样定义的:“非正式地说,如果对于一个数据对象没有额外的更新产生,最终对这个数据对象发起的读请求都会返回相同的结果。”这个定义只强调数据对象的值会收敛到一起。在1995年, Terry是这样定义最终一致性的:“所有服务器趋向于最终一致,也就是说,Bayou系统保证最终所有的服务器会收到所有的写入”。
由于今天大多数系统的实现其实是受到了Dynamo论文的影响,所以我们在本文的讨论中遵循Vogels对最终一致性的定义,我们相信他理解得更深入,在措辞上也更严谨。
最后要说明的一点是,最终一致性中的一致性,和ACID中的C是不同的两码事。
使用最终一致性的数据库
如果我们有一个最终一致性的key-value数据库,我们实现一个client的时候,通常的逻辑是这样的:
ecStorage.put(“anId”, “someData”);
while (ecStorage.get(“anId”) == null) sleep 1 second;
我们知道这个程序一定会终止:即便前几次“gets”调用无法返回我们写入的值,最终还是会返回的。
最终一致性数据的可能实现方式
最常规的实现方法也是由Werner Vogels在他论文中描述的:
N = 存储数据副本的总节点数目.
W = 一次写入需要等待Ack的数量,只有满足这个条件才能宣告一次写入的成功.
R = 一次读取需要查询的副本数目.
通常典型的N为3,数据是否异步复制到所有的3个副本上,取决于W的数值。W和R可以在1和3之间变化,取决于你期望什么样的性能和一致性。
如果我们设置W=1,发起的写操作只到达1个节点就宣告写入成功。从客户端的视角看,数据已经存储到其中一个节点,数据会被异步地复制到其他两个节点上去。
最终一致性,失败和数据丢失
当我们的存储系统是Dynamo key-value数据库时,如果W=1且R=1,我们看看会发生什么?
最简单的情况, 有3个节点:N1, N2, N3。
Client does a put on N1
Client does a get on N1
The program finishes.
另外一个程序的逻辑可能是:
Client does a put on N1
Client does a get on N2: receives null
Client does a get on N1
The program finishes.
当然,也可能是这样:
Client does a put on N1
Client does a get on N2: receives null
In parallel, the data was replicated from N1 to N2
Client does a get on N2: receives the data
The program finishes.
上面的这些场景是非常常见的,但是如果发生了故障,会怎样呢?毕竟故障是无法避免的。
下面是一个典型的例子:
Client does a put on N1
N1 crashes after the put but before the replication
Client does a get on N2: receives null
Client does a get on N3: receives null
...
请记住: 失败是一定会发生的,这也是为什么你首先选择最终一致性的原因
这个情况会在某一天终止吗?如果N1永久故障,因为在N1故障前并没有把数据复制出去。换句话说,你写客户端代码时按照一个最终一致性的存储系统来设计的,但是Dynamo实现中,如果W=1的情况下,其实Dynamo不是一个最终一致性的存储系统。更通用地说,一个可能丢失数据的存储系统,是不能被叫做一个最终一致性存储系统的。
这说明了什么?
这说明了一致性和持久性之间的强烈关联。在一致性模型中是没有数据丢失的。和传统的数据库系统的D是不同的(ACID中的D)。这在NoSQL/big data领域尤为重要,因为他们通常都部署在一般服务器上,相比传统的高端服务器,一般服务器发生故障的几率要高很多。
这是一个现实问题吗?
人们之所以花费这么多时间在讨论一致性模型上,是因为他们是有用的、而且也在真实生活中经常使用。背后的逻辑其实是:开发人员知道一致性模型后,他们可以在开发软件的时候利用它。因此,在Dynamo模型中描述W=1的场景时,它隐藏的含义应该是明确的。
为了达到最终一致性,在写入的时候把数据同步发送到多个节点是非常重要的。如果应用程序希望具备分区容忍性,那么在写入的时候把数据同步发送到多个机柜也是必须的,虽然相比只写入一个节点的情况,写入延时大了很多。
在跨数据中心的情况下,同步写的代价是非常大的。异步复制解决了性能问题,但同时,如果一个数据中心遭遇故障,也丢失了最终一致性。最终一致性不能笼统地用于描述整个系统。Stonebraker也曾经表达过类似的观点:
“Hence, eventual consistency cannot be guaranteed, because a transaction may be completely lost if a disaster occurs at a local cluster before the transaction has been successfully forwarded elsewhere.
(因此,最终一致性是不能保证的,因为在本地集群遭遇灾难的情况下,一个事务可能永久丢失,因为它并没在灾难发生之前被复制到其他地方)”。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31556431/viewspace-2218940/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31556431/viewspace-2218940/