关于CAP原理的讨论很多,而且通常会在分布式系统中产生误解。它规定:任何连网和分享数据的系统最多可以保证以下三个属性的两个:一致性、可用性和分区容错性。我在此不会详细介绍CAP,因为它涉及的方面很多,但是“三个中的两个”肯定是有误导性的——虽然概念上很容易理解。Brewer曾经指出这个问题,而且认同的声音很多,但是人们对于这个话题仍然存在很多的争议。底线是你不能牺牲分区容错性,但是似乎CAP在这个方面有一些偏差。
表面上,CAP将系统分成了三类。CA表示一个在保持一致性和可用性前提下实现完美可选性的网络系统。CP在牺牲一定可用性的前提下实现一致性和分区容错性,而AP则不考虑线性一致性的前提下实现可用性和分区容错性。显然,CA暗示系统只有在不存在网络分区时才保证一致性和可用性。然而,要说完全不存在网络分区,这显然是不太现实的。这正是许多争议发生的根源。
分区一定有。它们的出现有很多的原因。交换故障、NIC故障、链路层故障、服务器故障、进程故障等,都可能导致分区出现。即使系统不发生故障,也有其他原因可能引起分区,例如GC暂停或长时间延迟。我们要先接受这个事实,然后再继续分析。这意味着,只有当一个“CA”系统变为不CA时,它才是CA的。一旦出现分区,所有假设和所有保证都会以某一种方式产生严重后果。什么位置不会出现这个问题呢?
CAP的核心在于平衡折衷,但是它是一个排他原则。它告诉我们系统在特定的现实条件下不能做什么?这其中的区别是并非所有系统都能很好地符合这些模型。如果说Jepsen曾经教会我们什么,那么一定是让我们知道大多数系统都不符合这些分类,即使当初设计者说是符合的。在实践中,CAP并不是只有黑白两面。
Nicolas Liochon最近写了一系列非常不错的CAP文章。他很好地解释了这个既晦涩又容易误解的术语(比我解释得好多了),并且提出了一些非常有意义的观点。Nicolas认为,CA实际上应该看作为一种运营范畴的规范,而CP和AP则是关于行为的描述。我认同这一点,但是我的问题是它回避了一定会出现的平衡折衷。
我们知道网络分区是无法避免的。如果我们给应用程序这样的规定:“这个应用程序不会处理网络分区。如果出现网络分区,那么应用程序将部分失效,数据可能受到破坏,而且你可能不得不手工修复数据。”换而言之,我们在这里实际上要求的是CA,但是如果有一个分区出现,那么就可能属于CP;或者说,很不幸地同时失去了可用性和一致性。
在运营范畴内,CA实际上意味着当出现一个分区时,系统会摊开双手并发出信息:“我抛锚了!”如果我们指定系统不能在网络分区下正常工作,也就是说分区不在运营范畴之内。我们在地球上给一个设计飞往他拉星球大气层的太空飞船指定一个规范有什么意义呢?我们处于一个分区普遍存在的世界中,因此我们肯定要在运营范畴中支持分区。CA确定规定了一个运营范畴,但是你不能将它写到SLA然后交给客户看。通俗地说,在没有定义的时候,它只是一种“未定义行为”模式 ——系统是一致和可用的。CAP并不是一个完美的概念,但是在我看来,它确实很好地强调了构建分布式系统过程中需要考虑的一些基本折衷问题。无论我们有没有在书面写下来,它们都存在。如果写下来了,我们也无法保证可用性。在面对分区时,CAP似乎只能在一致性和可用性上面二选一。事实上,这里并不是只有两个选择。你可以选择AP、CP或两者都不选。两者都不选的问题是,我们很难推出它的原因,甚至很难给它定义。最终,它只是一种选择假象,因为我们不可能牺牲分区容错性。