分布式系统之 CAP 定理

什么是 CAP

CAP 定理,网上的别名比较多,比如 CAP 理论、CAP 原则、布鲁尔定理。大型网站几乎都是分布式的,分布式系统的最大难点,就是各个节点的状态如何同步,CAP 定理是这方面的基本定理,也是理解分布式系统的核心。

CAP 定理起源于加州大学柏克莱分校的计算机科学家埃里克·布鲁尔在 2000 年的分布式计算原理研讨会(PODC)上提出的一个猜想。 在 2002 年,麻省理工学院(MIT)的赛斯·吉尔伯特和南希·林奇发表了布鲁尔猜想的证明,使之成为一个定理。

CAP 定理有三个关键因素:

  • C consistency(一致性)
  • A availability(可用性)
  • P partition tolerance(分区容错性)

CAP 定理指出一个分布式系统最多只能同时满足一致性、可用性和分区容错性这三项中的两项。

一致性:指数据在多个副本之间能够保持一致的特性(强一致性)。

三种一致性策略:

  • 强一致性(Strong Consistency):强一致性要求任意时间下,读操作总是能取得最近一次写操作写入的数据。注意,这里依然是从存储系统客户端的角度来描述的,即便如强一致性的限制,也只要求在读取的时候能读到“最新”的数据就可以了,至于这个在上次写操作之后、这次读操作之前,对存储系统内部的数据是否是“最新”的并无要求。我们经常使用的传统关系型数据库,比如 Oracle、MySQL,它们都是符合强一致性的。

  • 弱一致性(Weak Consistency):弱一致性和强一致性相反,读操作并不能保证可以取得最新一次写操作写入的数据,也就是说,客户端可能读到最新的数据,也可能读不到最新的数据。这个“并不能保证”就有点“搞笑”了——都不确定能不能读到最新值,那它有什么用?其实它的应用也挺广泛的,最常见的例子就是缓存,比如一个静态资源被浏览器缓存起来,那么这之后只要是从缓存内取得的数据,使用者其实根本不知道这个数据是不是最新的,因为即便它实际有了更新,服务端也不会通知你。

  • 最终一致性(Eventual Consistency):最终一致性介于强一致性和弱一致性之间,写操作之后立即进行读操作,可能无法读到更新后的值,但是如果经过了一个指定的时间窗口,就能保证可以读到那个更新后的值。最终一致性可能是我们日常生活中最常见的一致性模型了。比如搜索引擎,搜索引擎的爬虫会定期爬取数据,并更新搜索数据,因此如果你的网站只是刚刚更新,可能还无法搜到这个更新内容,但只要是过了一定的时间窗口,它就会出现在搜索结果中了。

可用性:指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据)。

服务为了高可用,就要部署多个节点;数据为了高可用,就要存放多个备份。这里的数据,既包括数据本身,又包括数据的读写服务。这是因为:要让数据不丢失,冗余几乎是唯一的办法,因为再好的存储介质也架不住设备老化和各种原因的破坏;同理,为了数据访问服务能保持可用,包括保证足够的性能,必须要提供多个节点的读写操作服务,于是,我们不得不创建多个数据副本。那么一环扣一环,如果只有一份数据,是不存在一致性问题的,因为数据自己也只有一份,没法存在不一致,但有了数据副本,一致性就成为了问题。

分区容错性:指分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。

CAP 定理权衡

既然无法同时满足一致性、可用性和分区容错性这三个因素,不同场景选择不同因素。

CA without P:如果要一致性和可用性、则不要分区容错性。

CP without A:如果要一致性和分区容错性、则不要可用性。

AP wihtout C:如果要可用性和分区容错性、则不要一致性。

在讨论 CAP 定理的时候,P,也就是分区容错性,是必选项。具体来说,不同应用相互通过 API 调用,难免会遇到网络故障、弱网、请求超时、服务器宕机,都是无法预料、无法避免的。

对于门户网站来说,无论是显示的数据,还是图片、样式等等静态资源,通过 CDN 的方式,都可以把副本存放在离用户较近的节点,这样它们的获取可以减少延迟,提高用户体验。因此,这些系统联合起来,就形成了一个可以使用 CAP 讨论的分布式系统。

那么,很容易理解的是,且不用说网络故障而发生分区的情况,即便在正常情况下,这些信息并不需要具备那么严格的即时性,新闻早显示、晚显示几秒钟,乃至几分钟,都不是什么问题,上海的读者比北京的读者晚看到一会儿,也不是什么问题。但是,大型网站页面打不开,就是一个问题了,这显然会影响用户的体验。因此,从这个角度说,我们可以牺牲一致性,但需要尽量保证可用性,因此这是一个选择 AP 的例子。

事实上,对于大型的系统而言,我们往往不需要严格的一致性,但是我们希望保证可用性,因此在大多数情况下我们都会选择 AP。但是,有时情况却未必如此。

再比如买飞机票,在不考虑超售的情况下,一座一票,航空公司的网站当然可以采用上面类似的做法;有时,甚至在正常的情况下,余票的显示都可以不是非常准确的(比如显示有票可以避免显示这个具体数字)。但是,当客户真正在选座售票的时候,即扣款和出票的时候就不是这样的了,一致性必须优先保证。因为如果可用性保证不了,即有时候订票失败,用户最多也就是牢骚几句,这还可以接受,但要是出现一致性问题,即两个人订了同一个座位的票,那就是很严重的问题了。

从特性上说,甚至可以部分特性做到 CP,部分做到 AP,这都是有可能的。比如说,涉及钱的问题一定是 CP 吗?不一定,ATM 机就是一个很经典的例子,在网络故障发生时,ATM 会处于 stand-alone 模式,在这种模式下,用户依然可以执行查询余额等操作(很可能数额不准确),甚至还可以取款,但是这时的取款会有所限制,例如限制一个额度(银行承担风险),或者是限制只能给某些银行的卡取款,毕竟可用性和一致性的丢失会带来不同的风险和后果,两害相权取其轻。

打赏作者

您将是第一位评论人!

提醒
avatar