CAP 模型与 ACID、BASE 理论

1 有状态服务与无状态服务

分布式系统中的服务分为有状态服务与无状态服务两类。

无状态服务 (Stateless Service) 是指服务运行的实例不会在本地存储需要持久化的数据。这类服务处理一次请求所需的数据绝对不会从服务自身中获取,而是要么包含在请求内,要么从外部服务获取。举个例子,一个服务只提供了计算差值的能力。当一次请求到达服务端时,它会计算两个值的差值并返回给客户端。服务端并不保存任何数据信息,这种服务就是无状态服务。

相反,有状态服务 (Stateful Service) 是指服务的实例可以将请求或处理的数据随时进行备份,并在创建新的有状态服务时通过备份恢复这些数据,以实现数据持久化的目的。

在分布式系统中,有状态服务面临的困难要比无状态服务多得多。首先,有状态服务存在单点故障的问题,因此通常需要对服务进行集群部署。相比之下,无状态服务则可以通过横向扩展来解决单点故障问题,如下图所示:

无状态服务扩容
  • 起初服务 B 只有一个节点,服务 A 的请求都会到达服务 B,但是服务 B 经过横向扩展后服务 A 的请求有可能请求到服务 B 的集群内任意一个节点,并且无论服务 A 请求哪一个节点返回的结果都是相等的。

处理有状态服务的单点问题则相对复杂,不能像对无状态服务那样简单地进行横向扩展。以注册中心为例:假设有节点 A,并因为单点问题新增了节点 B。此时,节点 B 存储的服务数据与节点 A 存储的服务数据并不相等。即使在新增服务节点 B 后进行了数据同步,但在后续服务节点频繁上下线的过程中,服务消费者获取可用服务节点列表时可能会遇到数据不一致的情况。为了确保注册中心集群内各节点的数据一致性,我们需要借助一致性协议来解决这个问题。因此,有状态服务无法简单地像无状态服务那样通过添加服务节点来解决单点问题,而是需要在进行服务扩展时特别注意数据一致性问题。

此外,在分布式系统中,还需要考虑网络分区、服务可用性等问题。为了解决分布式系统中因为多节点部署而引入的众多问题,诞生出了分布式计算领域较为出名的 CAP 理论模型。

2 CAP 理论模型

CAP 理论又称为布鲁尔定理,它最早在 1998 年秋季提出,1999 年正式发表,并在 2000 年 7 月的 Symposium on Principles of Distributed Computing 大会上,由加州大学伯克利分校的 Eric Brewer 教授提出。2 年后,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 从理论上证明了 CAP 理论,确立了该理论的正确性。之后,CAP 理论正式成为分布式计算领域的公认定理。

CAP 理论的核心内容就是指出了一个分布式系统不能同时满足一致性 (Consistency)、可用性 (Availability)、分区容错性 (Partition Tolerance) 这三个基本要求,最多只能同时满足其中的两个,如下图所示:

CAP 理论
  • 一致性 (Consistency): 如果对某个数据项的更新操作成功执行,那么随后对系统中任意节点的读操作都应该返回更新后的数值。简而言之,所有节点在同一时刻看到的数据应该是相同的。在分布式系统中,数据一致性至关重要。当有状态服务进行横向扩展时,首要考虑的是数据一致性问题。
  • 可用性 (Availability):系统提供的服务应始终处于可用状态。只要客户端请求的节点不是故障节点,客户端的请求应该在有限的时间内收到返回结果,尽管这并不保证是最新的数据。如果服务本身发生故障,作为故障节点,它无法返回结果。因此,这里的服务可用性仅描述非故障节点。例如,当出现网络分区问题时,该服务无法与其他节点进行数据同步,可能导致数据不是最新的,但仍会向客户端返回响应。
  • 分区容错性 (Partition Tolerance):分布式系统在面临任何网络分区故障时,只要系统能在规定的时间内继续对外提供服务,则表明该分布式系统具备分区容错性。

对于“三选二”,并不是完全选择其中两个而放弃其中一个,这三者的制衡是有一个度的:

  • 上图中的 CA,看似舍弃了 P,实则并不能完全舍弃 P。在分布式系统中,因为各节点直接通过网络进行通信,所以网络分区很难避免,那么分区容错性就是必须要保证的。如果在设计分布式系统时选择了 CA,只能从概率上理解,假定了网络分区出现的可能性要比系统性错误低得多。但是即使认为概率很低,但还是有可能出现网络分区情况,当网络分区情况出现时,需要从原有的 CA 转为 AP 或者 CP。所以大多数情况下都是在一致性和可用性之间选择,寻找制衡点。
  • 上图中的 CP 更倾向于一致性,当发生网络延迟或者消息丢失时,两个节点之间的数据没有同步导致数据不一致,客户端希望得到的是最新数据。所以如果客户端请求到旧数据的节点,为了保证数据的一致性,则会对该请求响应错误信息,即使它能够正常处理请求,但是从客户端的角度来说,该服务可以理解为不可用的。
  • 上图中的 AP 更倾向于可用性,无论是否发生网络分区,客户端的请求都能获得正常的信息,只是如果两个节点的数据不一致,则返回的响应信息并不一定是最新的。

3 ACID 特性(强一致性)

如果说 CAP 理论模型中的一致性、可用性、分区容错性是对分布式系统的特性和要素进行的抽象和总结,那么 BASE 和 ACID 可以算是在实践中对 CAP 定理的补充和延展。

在介绍 ACID 之前,先介绍一下什么叫作事务。单个有状态服务中一次请求也许会存在多次修改数据的操作。比如在数据库服务中,有订单表和物流信息表,商家在一次发货操作中,数据库需要先在物流信息表内插入物流信息,然后在订单表中修改订单状态。在这个过程中,这两个操作是有关联的,第一个操作执行完成后必须保证第二个操作也正常执行完成,如果第二个操作没有正常执行完成,则这两个操作应该一起回滚,才能保证数据正确。这种由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元叫作事务。

事务有四个特征,简称 ACID:

  • 原子性 (Atomicity): 事务的所有操作要么全部成功执行,要么全部不执行。上述的商家发货就是一个典型的例子。
  • 一致性 (Consistency):事务的执行不能破坏数据库的完整性和一致性。
  • 隔离性 (Isolation):并发的事务需要相互隔离。
    • 有四种隔离级别,分别是 Read Uncommitted (未授权读取)Read Committed (授权读取)Repeatable Read (可重复读取)Serializable (串行化),详情可以参考 【MySQL 事务原理】
  • 持久性 (Durability):一个事务一旦提交,它对数据库中对应的数据状态变更就应该是永久性的。

事务分为本地事务分布式事务,本地事务是指基于单个服务访问单一数据库资源的事务。在单个数据库资源访问的情况下,很容易满足事务的 ACID 四个特性,并保证数据的强一致性。然而,在分布式架构流行的时代,服务和数据库资源不再是单一的,需要将多个数据库资源和多个服务的访问纳入同一个事务中。

分布式事务是指由不同执行逻辑单元组成的一次操作,这些执行逻辑单元属于不同的应用服务,并分布在不同的服务器上。分布式事务需要确保这些执行逻辑单元要么全部成功,要么全部失败。

举个例子,假设有一个购票系统,规定先扣除余额再出票。有两个乘客要购买相同航班的飞机票,但只剩一张票。两名乘客在不同的终端设备上同时发起购买行为,这必然会扣除用户的余额并出票。其中一名乘客购买成功,意味着另一名乘客将购买失败。这里的扣除余额和出票可以看作一系列操作逻辑单元。如果出票失败,余额也需要退回。为了保证购票操作的正常进行,就需要使用分布式事务。需要注意的是,在举例之前进行了一些条件限制,比如必须先扣除余额再出票。

满足单个节点的 ACID 特性相对容易,但要满足整个集群内所有节点之间的 ACID 特性就更具挑战性。目前业界存在一些分布式事务解决方案,如 TCC(Try-Confirm-Cancel)、XA(X/Open XA)等。

从 CAP 理论模型的角度来看,ACID 理论更加偏向一致性。无论是在单体服务架构还是分布式架构中,ACID 追求的是数据的强一致性。这四个特性正是为了实现数据强一致性而抽象出的约束条件。

4 BASE 理论(高可用性)

除一致性外,在大型的分布式系统中,高可用 (High Availability) 也是分布式系统的重要指标之一,它指的是通过设计来减少系统不能提供服务的时间。一般会用几个 9 来作为高可用的衡量标准,比如四个 9 就是 99.99%,意味着一年 8760 个小时中,系统不能提供服务的时间在 8.76 小时以下。在一些场景中,高可用相较于强一致性更加重要。

举个例子,假设用户 A 使用某银行 App 发起一笔跨行转账给用户 B,银行系统首先扣掉用户 A 的钱,然后提示用户 A 需要几小时后到账,在一段时间后增加用户 B 账户中的余额。这就是通过牺牲强一致性来提高可用性。BASE 就是基于该思想演化而来的。

BASE 是 Basically Available、Soft State、Eventually Consistent 的首字母缩写,其中涵盖了基本可用 (Basically Available)弱状态 (Soft State)最终一致性 (Eventually Consistent) 三个概念:

  • 基本可用 (Basically Available):分布式系统在出现不可预知故障时,允许损失部分可用性。
    • 响应时间上的损失:比如正常一个服务在 1 秒之内返回结果,可是由于断电等故障,返回结果的时间需要增加到 2 秒。
    • 功能上的损失:例如在“双 11”期间,由于消费者的购物行为激增,为了保障购物系统的稳定性,部分消费者可能会被引导到一个降级后的页面。
  • 弱状态 (Soft State):允许数据存在中间状态,并且该状态的存在不会影响系统的可用性,即允许系统在不同节点的数据副本之间进行数据备份的过程存在延时。
  • 最终一致性 (Eventually Consistent):系统中所有的数据副本在经过一段时间的同步后,最终能够达到一致的状态。因此最终一致性不需要实时保证一致性。

5 总结

CAP、ACID、BASE 三者的一致性有一些差异,CAP 的一致性更加关注一个服务的多个节点之间的数据一致性问题。ACID 的一致性更加强调无论此次事务执行是否成功,都应该保证这次事务执行后数据的完整性。BASE 的一致性则代表的是最终一致性。

CAP 和 BASE 都是分布式计算领域较为出名的理论模型,在设计理念上,ACID 是传统数据库常用的设计理念,追求强一致性模型。BASE 支持的是大型分布式系统,通过牺牲强一致性获得高可用。BASE 与 ACID 的设计哲学截然不同,在分布式系统设计的场景中,系统组件对一致性的要求是不同的,因此 ACID 和 BASE 又会结合使用。


欢迎关注我的公众号,第一时间获取文章更新:

微信公众号

相关内容