您的位置:首页 > 其它

最终一致性与CAP中CP模式的对比

2015-04-14 22:51 351 查看


最终一致性与CAP中CP模式的对比

最终一致性(Eventual Consistency/EC)是众所周知的概念。CAP理论同样也被大家所了解,它定义了一致性(Consistency)、可用性(Availability
)和分区容错性(Partition tolerance),它描述了某些分布式系统的特性,比如:CP类型分布式系统具有两个特性:一致性与分区容错区。

如果我们着眼于数据存储如何遵守自己的一致性模型,并比较它们的速度,哪一种会是最快的? EC(最终一致性)或者CP存储? 回答这个问题将是一个很好由头儿,让我们探究它们各自的定义、展现它们的一些局限性。



与流行的观点相反, 数据存储可以非常快


最终一致性

最终一致性由Werner Vogels定义于【E2】:“存储系统保证,若对象没有新的更新,最终所有的访问都将返回对象最后的更新值”。

让我们尝试一个假想key-value存储的一些实现。


实现1:尝试最简单的选择

void put(key, value){

// 什么也不做

}

value get(key){

// 嘿, 很容易实现! 我假装没有收到写请求,这就足够了!

throw “no value for this key”

}

这是一个最终一致性存储? 不,它不是,因为它从不会返回最后的更新值。要成为一个最终一致性存储,需要“最终[......]返回最后的更新值”。这是此实现没有做到的,它永远不会返回最后的更新值。

让我们尝试另外一个实现:


实现2:试图快速读取

void put(key, value){

doRealPut(key, value) // 真正地干活儿

}

value get(key){

if (random(2) == 1) // 50%的时间

throw “no value for this key”

else

return doRealGet(key)

// 50%的时间,我假装没有收到前一次的插入,两次返回一次值。

}

这是一个最终一致性存储? 再次:它不是。因为没遵守这个属性:“最终所有的访问将返回最后的更新值”
。不满足条件”所有的访问“。

不管怎样也不能阻止我们干可笑的事情,比如:


实现3:玩个文字游戏

void put(key, value){

doRealPut(key, value)

}

value get(key){

if (currentDate.year < 2020)

throw “no value for this key”

else

return doRealGet(key)

// 我在2020年以前将赢得所有的读取benchmarks测试。

}

上面最后这个实现符合定义,但它是在玩文字游戏。在日终时,我们必须返回最新值的事实很重要,因为我们不能欺骗可用性。

最后,一种强实时存储实现,具有严格的SLA与“使它在预期时间内返回或者中止”策略,不符合最终一致的定义:


实现4:尝试最终一致性的强实时系统

void put(key, value){

doRealPut(key, value)

}

value get(key){

try (timeLimit = 10 ms) { // 在10毫秒内返回或抛出

return doRealGet(key)

} catch (TimeOutException) {

// 最大响应时间是10毫秒!

throw “no value for this key”

}

}

这种行为有时很管用。然而,一个最终一致性的存储不被允许这样做:它打破了一致性契约。就象第二个实现,“最终所有的访问将返回最后的更新”的承诺被打破。

不过,此行为可用于任何存储,最终一致性或不是。实际上,可以认为在许多存储上都有设置类似超时的选项(再次,最终一致性或不是)


CAP与CP

如果你正在阅读本文,你已经看到了CAP及其定义:”一致性(Consistency)、可用性(Availability)、分区容错性(Partition
tolerance):选取其中两个“。CAP是由Eric
Brewer首次在2000年提出的一个猜想【C1】,在2002年,由Seth Gilbert 和Nancy Lynch证明【C2】。

让我们使用被证明过的定义【C2】:

一致性(Consistency):“原子性,可串行,一致性【...】。所有操作必须存在一个整体上的顺序,这样每个操作看起来好像是在一个瞬间内完成。这相当于要求,分布式共享内存系统对请求的处理,表现得就像它们在单个节点上执行一样,一次一个地响应操作”。

可用性(Availability):“一个分布式系统持续可用,被非故障节点收到的请求必须有响应
”。

分区容错性(Partition
tolerance):“允许网络丢失任意多个从一个节点发送到另一节点的消息。当网络分区发生时,从一个分区中节点发向其它分区中节点的所有消息将丢失”。

这让我们有一个CP系统的简单实现:


实现1:CP做起来很简单

void put(key, value){

throw “not available”

}

value get(key){

throw “not available”

}

这个“什么也不做”的实现,完全符合CP的定义:它不完全可用--实际上根本不可用--但它是一致性的。实际在【C2】中提到:“如果不要求可用性,那么很容易实现原子性和分区容错性。这个简单的系统忽略所有的请求,来满足这些条件要求”。


CAP与AP

AP存储有所不同吗? 不见得:CAP理论没有要求AP实现一致性,那怕是最低限度的一致性。【C2】提到“如果不要求原子一致性,它可以提供高可用性和分区容错性。如果没有一致性要求,服务可简单地对每个请求都返回v0(一个初始值)”。
这意味着,我们可用非最终一致性的最小实现,来做一个具有可用性与分区容错性的存储:


实现2:AP也很容易

void put(key, value){

// do nothing

}

value get(key){

throw “no value for this key”

}



是一个有用处的CP存储吗?


结论

对于任何合理的数据存储实现,最终一致性的定义导致一个非常明确的行为。而CAP理论中的AP和CP定义更为宽松,并允许构建无用的,但完全地CP或AP存储。

一个直接的推论:任何一个在分区产生时最终崩溃的简单应用,可获得CP-分区容错性奖项。


参考

[C1] Eric A. Brewer, PODC Keynote, July 19, 2000, Towards Robust Distributed Systems

[C2] Gilbert and Lynch. Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant
web services. ACM SIGACT News (2002)

[E2] Werner Vogels, Eventually Consistent, ACM Queue, Vol.6 No.6, 2008

原文链接:http://thislongrun.blogspot.com/2015/03/comparing-eventually-consistent-and-cp_11.html
翻 译::歪脖大肚子Q
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: