Cap理论又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式系统来说,不可能同时满足如下三点:
一致性(Consistency)
可用性(Availability)
分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。)
一致性
所谓一致性,指的是数据的一致性,在一个分布式数据库系统中,所有集群节点都保持同一份最新数据副本,所有客户端同一时刻访问同一个数据都将是一致的,即“all nodes see the same data at the same time”。
如果所有客户端能时刻看到一致的数据,不存在中间状态,这个叫强一致性。如果允许存在中间状态,经过一段时间数据达到一致性,这个叫最终一致性,或说弱一致性,后面的BASE理论将介绍最终一致性。
可用性
可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内获取一个非错响应,但是不保证获取的数据为最新数据。“有限的时间内”是指,对于用户的一个操作请求,系统必须能够在指定的时间内返回对应的处理结果,如果超过了这个时间范围,那么系统就被认为是不可用的。简单来说就是请求必须要有非错响应,假设不响应或是错误的响应(比如http请求返回404,400等)则认为是不可用。
分区容错性
分区容错性,通常是指发生了网络分区,分布式系统在这种情况下需要有容错能力。这么说有点抽象,下面给出一个图及实际网络分区以说明:
如上图,在一个分布式数据库系统中,由于网络原因,原来作为一个整体的集群系统被一分为二,假设现在这两个分区目前都能被客户端访问到,假设都能写成功 。那么结果就是同一个数据出现不一致,这种情况是牺牲了一致性,保全了可用性()。如果出现分区后,系统不允许写,或者是拥有多数节点的分区允许写,当网络分区恢复成一个整体后,数据是能达到一致的,这种情况牺牲可用性(分区二不允许写)。简单来说,分区容错性指的是,当网络分区出现,分布式系统必须就当前操作在一致性与可用性之间作出选择。由于网络分区并不是可控的,所以分区容错性是Cap理论中必须要实现的,或说是前提,分布式系统在满足P的情况下选择AP或是CP。
因此,分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。 比如 ZooKeeper、HBase 就是 CP 架构,强调一致性,Cassandra、Eureka 就是 AP 架构,注重可用性,Nacos 不仅支持 CP 架构也支持 AP 架构,可根据实际业务场景进行选择。
在发生网络发区的情况下,强一致性和强可用性是矛盾的。假设发生网络分区后(如上图分区一与分区二),为了保证一致性(C),分区一与分区二必须有一个分区处于不可写或说写了不会提交的状态。那么这个就违反了可用性(A)原则。假设两个分区都可写(保证了可用性),很明显,当写的是同一个数据的情况,一致性就被违反了。
当然,如果没有发生分区,分布式系统是能同时保证一致性和可用性的。
eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论。BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。
基本可用(Basically Available)
指分布式系统在出现不可预知故障的时候,允许损失部分可用性。损失部分可用性可以是响应时间上的损失或系统功能的损失,如响应时间变慢,或是核心功能可用但非核心功能不可用。
软状态( Soft State)
指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。
最终一致( Eventual Consistency)
强调的是所有的数据更新操作,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
强一致性:all nodes see the same data at the same time,所有节点在同一时刻看到的数据总是一致的。
弱一致性:节点之间的数据同步存在延时,系统不保证在同一时刻所有节点能看到一致的数据,也不保证在一定时间内系统数据会达到一致,只是尽量保证。
最终一致性:节点之间的数据同步存在延时,系统不保证在同一时刻所有节点能看到一致的数据。但保证会在一定的时间内,系统数据最终达到一致。实现最终一致性的方法有很多,如在读写时检测到副本数据不一致可以进行修复,结合异步定时修复等方法使数据达到最终一致性。