请停止调用数据库CP或AP(2015)

2020-09-07 08:58:30

这篇博客文章已被再次翻译成俄语、日语、中文和中文。有关CAP问题的更多详细信息,以及替代方案的建议,请参阅我的论文“CAP定理批判”。

Jeff Hodges在他优秀的博客文章“面向年轻人的分布式系统笔记”中建议您使用CAP定理来批判系统。很多人把这个建议放在心上,把他们的系统描述为“CP”(在网络分区下一致但不可用)、“AP”(在网络分区下可用但不一致),或者有时是“CA”(意思是“我几乎5年前还没有读过Coda的帖子”)。

我同意杰夫的所有其他观点,但是关于CAP定理,我必须不同意。CAP定理过于简单化,误解范围太广,对刻画系统没有多大用处。因此,我要求我们停止所有对CAP定理的引用,停止谈论CAP定理,把这可怜的东西放在一边。相反,我们应该使用更精确的术语来解释我们的权衡。

(是的,我意识到就我要求人们停止写作的主题写一篇博客文章是多么具有讽刺意味。但至少它给了我一个URL,当人们问我为什么我不喜欢他们谈论CAP定理时,我可以给他们一个URL。另外,如果这有点夸张,很抱歉,但至少这是一个引用了大量文献的咆哮。)。

如果您想将CAP作为一个定理来引用(而不是数据库营销材料中的模糊手势概念),则必须精确。数学需要精确度。只有当你使用与校样中使用的词含义相同的词时,校样才成立。而且校样使用了非常特殊的定义:

CAP中的一致性实际上意味着可线性化,这是一个非常具体(并且非常强)的一致性概念。特别值得一提的是,它与酸中的C没有任何关系,尽管C也代表“一致性”。下面我解释线性化的含义。

CAP中的可用性被定义为“系统中无故障的[数据库]节点接收的每个请求都必须导致[无错误]响应”。仅有一些节点能够处理请求是不够的:任何非故障节点都需要能够处理它。许多所谓的“高可用性”(即低停机时间)系统实际上并不符合这个可用性定义。

分区容错(命名严重错误)基本上意味着您正在通过可能延迟或丢弃消息的异步网络进行通信。互联网和我们所有的数据中心都有这个属性,所以在这件事上你没有任何选择。

还要注意的是,CAP定理不仅描述了任何旧系统,而且描述了系统的一个非常具体的模型:

CAP系统模型是单个读写寄存器-仅此而已。例如,CAP定理没有说明涉及多个对象的事务:它们只是超出了定理的范围,除非您能以某种方式将它们减少到单个寄存器。

CAP定理考虑的唯一故障是网络分区(即节点保持正常,但其中一些节点之间的网络不工作)。这种故障绝对会发生,但这不是唯一可能出错的事情:节点取消崩溃或重新启动,磁盘空间可能用完,软件中可能出现错误,等等。在构建分布式系统时,您需要考虑更广泛的权衡,过于关注CAP定理会导致忽略其他重要的问题。在构建分布式系统时,您需要考虑更广泛的权衡,而过于关注CAP定理会导致忽略其他重要的问题。在构建分布式系统时,您需要考虑更广泛的权衡,过于关注CAP定理会导致忽略其他重要问题。

而且,CAP定理没有提到延迟,人们往往更关心延迟而不是可用性。事实上,CAP可用的系统被允许任意缓慢地响应,并且仍然可以被称为“可用”。冒昧地说,如果加载一个页面需要2分钟,我猜您的用户不会说您的系统“可用”。

如果你的用词符合证明的精确定义,那么CAP定理就适用于你。但是,如果您使用的是一致性或可用性的其他概念,则不能期望CAP定理仍然适用。当然,这并不意味着你可以突然做一些不可能的事情,只需重新定义一些词!这只意味着你不能求助于CAP定理来指导,你也不能用CAP定理来证明你的观点。

如果CAP定理不适用,这意味着您必须自己考虑权衡。您可以使用自己对这些词的定义来推理一致性和可用性,并且欢迎您证明自己的定理。但是请不要叫它CAP定理,因为这个名字已经被取走了。

如果您不熟悉线性化(即CAP意义上的“一致性”),让我简要地解释一下。正式的定义并不是完全直截了当的,但非正式地陈述的关键思想是这样的:

如果操作B在操作A成功完成后开始,则操作B必须看到系统处于与操作A完成时相同的状态或更新的状态。

为了使这一点更加明确,请考虑一个不可线性化的系统示例。请参阅下面的图表(从我的书中未发布的一章中偷偷预览):

这张图显示,爱丽丝和鲍勃在同一个房间里,两人都在查看手机,想知道2014年足球世界杯决赛的结果。就在最终比分公布后,爱丽丝刷新了页面,看到获胜者宣布了,并兴奋地告诉了鲍勃这件事。波波难以置信地在他自己的手机上点击了重新加载,但他的请求去了一个数据库副本,那个孤岛,所以他的手机显示,游戏仍在进行中。

如果Alice和Bob同时点击了reload,那么如果他们得到两个不同的查询结果也就不足为奇了,因为他们不知道服务器处理他们各自的请求的确切时间。然而,Bob知道他在听到Alice惊呼最终得分后点击了重新加载按钮(启动了他的查询),因此他希望他的查询结果至少和Alice的一样新。他得到的查询结果陈旧的事实违反了可识别性。

知道Bob的请求严格地发生在Alice的请求之后(即它们不是并发的)取决于Bob通过单独的通信信道(在本例中是IRL音频)听说Alice的查询结果这一事实。如果鲍勃没有从爱丽丝那里听到游戏结束的消息,他就不会知道他的查询结果已经过时了。

如果你正在构建一个数据库,你不知道你的客户可能有什么样的反向通道。因此,如果您希望在数据库中提供线性化语义(CAP一致性),则需要使其看起来好像只有一个数据副本,即使在多个位置可能有数据的副本(副本、缓存)也是如此。

这是一个相当昂贵的保证,因为它需要大量的协调。即使您计算机中的CPU也不能提供对本地RAM的线性化访问!在现代CPU上,您需要使用显式内存屏障指令才能获得线性化。甚至测试一个系统是否提供线性化也是很棘手的。

让我们简要讨论一下在网络分区的情况下需要放弃线性化或可用性。

假设您的数据库副本位于两个不同的数据中心。复制的确切方法目前并不重要-它可以是单引导器(主/从)、多引导器(主/主)或基于仲裁的复制(Dynamo样式)。复制的要求是,每当将数据写入一个数据中心时,也必须将其写入另一个数据中心的副本。假设客户端仅连接到一个数据中心,则在进行复制的两个数据中心之间必须有网络链路。

现在假设网络链路中断-这就是我们对网络分区的意思。什么东西?

继续允许应用程序写入数据库,因此它在两个数据中心都保持完全可用。但是,只要复制链接中断,在一个数据中心中写入的任何更改都不会出现在另一个数据中心中。这违背了线性化(根据前面的示例,Alice可以连接到DC 1,而Bobb可以连接到DC 2)。

如果您不想失去线性化,则必须确保在一个数据中心(您可以将其称为领导者)进行所有读写操作。在另一个数据中心(由于复制链路故障,该数据中心可能不是最新的),数据库必须停止接受读取和写入,直到网络分区修复并且数据库再次同步。因此,尽管非LEADER数据库没有出现故障,但它不能处理请求,因此它不是CAP可用的。

(顺便说一下,这实质上是CAP定理的证明。非那样做不行。(此示例使用两个数据中心,但它同样适用于单个数据中心内的网络问题。我只是发现,当我将其想象为两个数据中心时,会更容易考虑。)。

请注意,在选项2中的名义上“不可用”的情况下,我们仍然很高兴地在其中一个数据中心处理请求。因此,如果系统选择了线性化(即它不是CAP可用的),这并不一定意味着网络分区会自动导致应用程序中断。如果您可以将所有客户端都转移到使用领先的数据中心,那么这些客户端实际上将完全不会出现停机。

实践中的可用性并不完全对应于CAP-可用性。您应用程序的可用性可能是用一些SLA来衡量的(例如,99.9%的格式良好的请求必须在1秒内返回成功响应),但是这样的SLA可以通过CAP可用和CAP不可用系统来满足。

在实践中,多数据中心系统通常设计为异步复制,因此是不可线性化的。然而,这样选择的原因通常是广域网的延迟,而不仅仅是想要容忍数据中心和网络故障。

在CAP定理对一致性(线性化)和可用性的严格定义下,系统表现如何?

例如,以具有单个引导者的任何复制数据库为例,这是在大多数关系数据库中设置复制的标准方式。在此配置中,如果客户端与引导者分区,则它不能写入数据库。即使它可能能够从跟随者读取(仅区域复制副本),它不能写入的事实意味着任何单引导者设置都不是CAP可用的。不要介意这样的配置通常被宣传为“高可用性”。

如果单引线复制不能使用CAP,这会使其成为“CP”吗?等等,别这么快。如果您允许应用程序从跟随者进行读取,并且复制是异步的(大多数数据库中的默认设置),则当您从跟随者进行读取时,跟随者可能会稍微落后于领先者。在这种情况下,您的读取将不可线性化,即不能与CAP一致。

此外,具有快照隔离/MVCC的数据库是故意不可线性化的,因为实施可线性化会降低数据库可以提供的并发级别。例如,PostgreSQL的SSI提供可串行化但不提供可线性化,而Oracle既不提供可串行化又不提供线性化。仅仅因为数据库被标记为“ACID”并不意味着它满足CAP定理的一致性定义。

因此,这些系统既不是CAP一致的,也不是CAP可用的。他们既不是“CP”也不是“AP”,他们就是“P”,不管那是什么意思。(是的,“三选二”公式确实允许您从三个中只选一个,甚至一个也不选!)。

“NoSQL”怎么样?以MongoDB为例:它每个分片只有一个领导者(或者至少应该是这样,如果它不是在分裂大脑模式下),所以上面的论点不是CAP-Available。而Kyle最近表明,即使在最高的一致性设置下,它也允许不可线性化的读取,因此它也不是CAP一致的。

还有迪纳摩衍生品,如Riak、Cassandra和Voldemort,它们通常被称为“AP”,因为它们优化了高可用性?这取决于您的设置。如果您接受单个副本读取和写入(R=W=1),则它们确实是CAP可用的。但是,如果您需要仲裁读取和写入(R+W&>N),并且您有一个网络分区,则分区少数端上的客户机无法达到仲裁,因此仲裁操作不可CAP使用(至少暂时如此,直到数据库在少数端设置其他副本)。

您有时会看到有人声称仲裁读取和写入可确保线性化,但我认为依赖它是不明智的-草率仲裁和读取修复等功能的微妙组合可能会导致棘手的边缘情况,其中删除的数据会被恢复,或者值的复本数量低于原始W(违反仲裁条件),或者复制结点的数量增加到原始N以上(再次违反仲裁条件)。所有这些都会导致不可线性化的结果。

这些都是不错的系统:人们总是在生产中成功地使用它们。然而,到目前为止,我们还不能严格地将它们归类为“AP”或“CP”,要么是因为它取决于特定的操作或配置,要么是因为系统既不满足CAP定理关于一致性或可用性的严格定义。

那动物园管理员呢?它使用一致的算法,所以人们通常认为它是一个选择一致性而不是可用性的明确案例(即“CP系统”)。

但是,如果您查看ZooKeeper文档,就会发现它们非常清楚地表明,默认情况下,ZooKeeper不提供可线性化的读取。每个客户端都连接到一个服务器节点,当您进行读取时,即使在另一个节点上有更多最新写入,您也只能看到该节点上的数据。这使得读取速度比每次读取都要集合法定数量或联系领导的情况快得多,但这也意味着ZooKeeper在默认情况下不满足CAP定理的一致性定义。

通过在读取之前使用synccommand命令,可以在ZooKeeper中进行可线性化读取。不过,这不是默认设置,因为它会影响性能。人们确实会使用同步,但通常不是所有时间都使用同步。

动物园管理员有空吗?嗯,ZK需要多数法定人数才能达成共识,也就是说,才能处理写入。如果您的分区一边是多数节点,另一边是少数节点,那么多数端将继续运行,但是少数端上的节点无法处理写入,即使这些节点已启动。因此,在分区下,ZK中的写入不能CAP-Available(即使多数端可以继续处理写入)。

为了增加乐趣,ZooKeeper 3.4.0增加了一个只读模式,在该模式下,分区的主要一侧的节点可以继续为读请求提供服务-不需要仲裁!此只读模式为CAP-Available。因此,ZooKeeper在默认情况下既不是CAP一致(CP),也不是CAP可用(AP)-它实际上只是“P”。但是,如果您愿意,您可以通过调用sync将其设置为CP,而对于读取(但不是写入),如果您打开正确的选项,它实际上是AP。

但这太让人恼火了。说动物园管理员“不一致”,仅仅因为它不能被Default线性化,真的很严重地歪曲了它的特点。它实际上提供了极好的一致性!它提供原子广播(可简化为共识)与因果一致性的会话保证相结合-这比读写、单调读取和一致前缀读取加在一起更强。文档说它提供顺序一致性,但它本身被低估了,因为ZooKeeper的保证实际上比顺序一致性强得多。

正如ZooKeeper演示的那样,在存在分区的情况下,系统既不是CAP一致的,也不是CAP可用的,并且在缺省情况下,甚至在没有分区的情况下都不能线性化,这是非常合理的。(我猜在Abadi的PACELC框架中应该是PC/EL,但我并不觉得这比CAP更有启发性。)。

我们甚至不能明确地将一个数据存储归类为“AP”或“CP”,这一事实应该告诉我们一些事情:它们根本不是描述系统的正确标签。

我认为我们应该停止将数据存储放入“AP”或“CP”存储桶中,因为:

在CAP定理的定义下,许多系统既不一致也不可用。然而,我从来没有听过任何人把他们的系统只称为“P”,大概是因为它看起来很糟糕。但这并不坏-它可能是一个非常合理的设计,只是不适合两个CP/AP桶中的一个。

尽管大多数软件不能整齐地放入这两个桶中的一个,但人们还是试图将软件塞进这两个桶中的一个,从而不可避免地将“一致性”或“可用性”的含义更改为任何适合他们的定义。不幸的是,如果单词的意思改变了,CAP定理就不再适用,因此CP/AP的区别就变得完全没有意义了。

将系统放在两个桶中的一个桶中会丢失大量的微妙之处。在设计分布式系统时,需要考虑容错性、延迟、编程模型的简单性、可操作性等诸多因素。将这种微妙之处编码在一位信息中是根本不可能的。例如,即使ZooKeeper有一个“AP”只读模式,该模式仍然提供历史写入的总排序,这比Riak或Cassandra等系统中的“AP”要强得多-所以把它们放在同一个桶中是荒谬的。

就连埃里克·布鲁尔(Eric Brewer)也承认,CAP具有误导性,过于简单化。在2000年,它的意思是开始一场关于分布式数据系统权衡的讨论,而且做得非常好。它并不打算成为突破性的正式结果,也不打算成为数据系统的严格分类方案。15年后,我们现在有更多具有不同一致性和容错模型的工具可供选择。CAP已经达到了它的目的,现在是时候继续前进了。

如果CP和AP不适合描述和批评系统,您应该使用什么来代替?我不认为有一个正确的答案。许多人对这些问题进行了深思熟虑,并提出了一些术语和模型来帮助我们理解问题。要了解这些想法,你必须更深入地研究文学作品。

道格·特里的论文是一个很好的起点,他在论文中用棒球的例子解释了各种不同水平的最终一致性。即使(像我一样)你不是美国人,对棒球一无所知,它也是非常易读和清晰的。

如果您对事务隔离模型感兴趣(这与分布式副本的一致性不同,但有一定的关系),我的小项目Hermitage可能是相关的。

Peter Bailis等人探讨了副本一致性、事务隔离和可用性之间的联系。(这篇论文还解释了凯尔·金斯伯里喜欢展示的一致性等级等级的含义。)。

当你读完这些之后,你应该准备好更深入地研究文学作品了。我在这篇文章中散布了大量的论文链接。一定要看一看:很多专家已经为你想出了很多东西。

作为最后的手段,如果你不能面对阅读原文,我建议你看看我的书,它以一种平易近人的方式总结了最重要的思想。(你看,我非常努力地不让这篇帖子成为推销的对象。)。

如果你想更具体地了解如何正确使用动物园管理员,弗拉维奥·琼奎拉和本杰明·里德的书是一本好书。

无论你选择哪种学习方式,我都鼓励你保持好奇心和耐心--这件事来之不易。但这是值得的,因为你学会了。

.