CAP定理是分布式系统设计中的一个基本定理,它指出在一个分布式计算系统中,一致性(Consistency)、可用性(Availability)、分区容忍性(Partition Tolerance)三者不可同时实现,最多只能同时满足其中的两个。
一致性(Consistency)
所有节点在同一时间的数据视图是一致的。即,如果系统接受了更新操作,在之后的所有访问操作中都能获取到最新的数据。
可用性(Availability)
系统保证每个非故障节点在有限时间内返回合理的响应,即系统对于用户的每一个操作请求总是能够在有限时间内返回结果。
分区容忍性(Partition Tolerance)
系统在遇到网络分区故障时仍然能够继续运行。即,系统能够在网络发生故障或分区时继续对外提供服务。
根据CAP定理,在分布式系统设计中,当网络出现分区时,系统需要在一致性和可用性之间做出权衡。分布式系统往往会选择牺牲一致性以保证可用性和分区容忍性,或者牺牲可用性以保证一致性和分区容忍性。
CAP定理的实际含义是:在分布式系统中,由于网络分区的存在,系统无法同时保证一致性、可用性和分区容忍性,因此在设计分布式系统时需要根据具体需求和场景做出权衡。
CAP 三要素之间的冲突的关系
在分布式系统中,由于网络分区的存在,系统无法同时保证一致性、可用性和分区容忍性,因此在设计分布式系统时需要根据具体需求和场景做出权衡。
CA without P
如果放弃分区容忍性(CA without P):强调 单节点, 单副本,或者只有一个正本,没有副本。简单说,CA 将所有数据都放在一个分布式节点上,这同时放弃了系统的可扩展性, 不属于 分布式系统范围了。
意味着我们将假设节点之间通信永远是可靠的。永远可靠的通信在分布式系统中必定不成立的,这不是你想不想的问题,而是只要用到网络来共享数据,分区现象就会始终存在。在现实中,最容易找到放弃分区容忍性的例子便是传统的关系数据库集群,这样的集群虽然依然采用由网络连接的多个节点来协同工作,但数据却不是通过网络来实现共享的。以 Oracle 的 RAC 集群为例,它的每一个节点均有自己独立的 SGA、重做日志、回滚日志等部件,但各个节点是通过共享存储中的同一份数据文件和控制文件来获取数据的,通过共享磁盘的方式来避免出现网络分区。因而 Oracle RAC 虽然也是由多个实例组成的数据库,但它并不能称作是分布式数据库。
CP without A
强调副本之间的 强一致性, 意味着低性能。一旦系统遇到故障时,受影响的服务器需要等待一段时间,在恢复期间无法对外提供正常的服务。
意味着我们将假设一旦网络发生分区,节点之间的信息同步时间可以无限制地延长,此时,问题相当于退化到前面"全局事务"中讨论的一个系统使用多个数据源的场景之中,我们可以通过 2PC/3PC 等手段,同时获得分区容忍性和一致性。在现实中,选择放弃可用性的 CP 系统情况一般用于对数据质量要求很高的场合中,除了 DTP 模型的分布式数据库事务外,著名的 HBase 也是属于 CP 系统,以 HBase 集群为例,假如某个 RegionServer 宕机了,这个 RegionServer 持有的所有键值范围都将离线,直到数据恢复过程完成为止,这个过程要消耗的时间是无法预先估计的。
AP without C
强调副本之间的 高性能, 意味着 弱一致性。这里的放弃一致性是指放弃数据强一致性,而保留数据的最终一致性。系统无法实时保持数据的一致,但承诺在一个限定的时间窗口内,数据最终能够达到一致的状态。
意味着我们将假设一旦发生分区,节点之间所提供的数据可能不一致。选择放弃一致性的 AP 系统目前是设计分布式系统的主流选择,因为 P 是分布式网络的天然属性,你再不想要也无法丢弃;而 A 通常是建设分布式的目的,如果可用性随着节点数量增加反而降低的话,很多分布式系统可能就失去了存在的价值,除非银行、证券这些涉及金钱交易的服务,宁可中断也不能出错,否则多数系统是不能容忍节点越多可用性反而越低的。目前大多数 NoSQL 库和支持分布式的缓存框架都是 AP 系统,以 Redis 集群为例,如果某个 Redis 节点出现网络分区,那仍不妨碍各个节点以自己本地存储的数据对外提供缓存服务,但这时有可能出现请求分配到不同节点时返回给客户端的是不一致的数据
即使我们尝试去优化这三个要素,但是最多只能实现两个要素。CA 、CP、AP 只能 三选一:
CAP理论告诉我们,一致性、可用性和分区容错性是相互冲突的。
作为 分布式系统, 分区容错性 P 是必不可少的, 所以只能在 AP 、CP之间,二选一。
因此,CAP定理给我们提供了一个有限的选择空间,我们需要根据具体的需求来选择适当的一致性模型。
- 要么 CP 强一致性
- 要么 AP 高可用性
二者 不可兼得, 天然冲突。
BASE理论
BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。
从上面我们知道了,CAP是不可能全满足的,所以BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。
BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
-
Basically Available(基本可用):基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性----注意,这绝不等价于系统不可用。比如:(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒 (2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面
-
Soft state(软状态):软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
-
Eventually consistent(最终一致性):最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性
常用中间件的 CAP 定理
在分布式系统中,根据 CAP 定理,系统往往需要在一致性(Consistency)和可用性(Availability)之间做出权衡,选择更偏向于 CP(Consistency and Partition Tolerance)或者 AP(Availability and Partition Tolerance)的设计方向。以下是一些常见的 CP 或者 AP 的组件:
AP 组件(Availability and Partition Tolerance)
redis Cluster 是 AP 型
首先,分析一下 redis Cluster 的分区容错性(P)
Redis Cluster 采用去中心化的架构,节点之间通过 Gossip 协议来进行信息交换。Gossip 协议就像在集群中 "传播小道消息",每个节点 周期性地向其他节点发送状态信息, 也会接收其他节点传来的信息。这种方式使得集群能够快速感知到网络分区的情况。
当网络分区发生时,例如部分节点之间无法通信,Redis Cluster 依然能够正常工作。
它会根据集群配置和节点状态,让每个分区内的节点尽可能地独立运行。
例如,在数据分片(Redis Cluster 将数据分成 16384 个槽位,分布在不同节点上)的情况下,每个分区内的节点可以继续处理自己负责槽位的读写请求,保证系统不会因为网络分区而完全瘫痪,体现了良好的分区容错能力。
再来,分析一下 redis Cluster 的可用性(A)
在正常情况下,客户端可以向任意主节点发送读写请求。即使在节点故障转移过程中,大部分读写请求依然能够得到处理。
Redis Cluster 具备高效的故障转移机制。每个主节点都有对应的从节点,当主节点出现故障时,从节点会通过选举机制快速晋升为主节点。
例如,假设一个主节点因为硬件故障或者网络问题无法正常工作,从节点能够在很短的时间(通常在毫秒级)内检测到这种情况,并开始竞选成为新的主节点。
一旦竞选成功,新的主节点就可以接收客户端的读写请求,保证服务的可用性。
最后,分析一下 redis Cluster 的一致性(C)
Redis Cluster 没有选择强一致性,而是采用了最终一致性。
这是因为在保证高可用性和分区容错性的同时,强一致性会带来性能上的巨大损耗。
例如,在主从复制过程中,如果要求每次写操作都必须等待从节点同步完成才能返回成功,会大大增加写操作的延迟。
Redis Cluster 通过异步复制的方式来维护数据的一致性。
- 主节点接收写请求后,会异步地将数据复制给从节点。
- 在正常情况下,这种异步复制能够快速地将数据传播到从节点。
- 当出现故障转移时,新晋升的主节点可能会丢失一部分还没来得及复制的数据,但系统会在后续通过数据恢复机制(如从其他节点获取丢失的数据副本)来使数据最终达到一致。
这种对一致性的权衡使得 Redis Cluster 更符合 AP 系统的特点。
总之 :redis Cluster 是 ap 型。
Cassandra 属于 AP
Apache Cassandra 是由 Apache 软件基金会维护的 开源 NoSQL 数据库。
- Cassandra 是一个列式数据库,允许您在分布式网络上存储数据。
- Cassandra 与 MongoDB 不同 ,Cassandra 拥有一个无主的架构。
因为 Cassandra 没有主节点,所以所有节点必须连续可用。
然而,Cassandra 允许客户机在任何时候向任何节点写入数据并尽快协调不一致,从而提供了最终的一致性。
按照 CAP 定理去分析, Cassandra 是一个 AP 数据库 ,它提供高并发,但不能强一致性。
Eureka 属于 AP
首先看看 Eureka 可用性(A)
Eureka 采用去中心化的架构,各个 Eureka Server 之间相互对等,没有主从之分。
这意味着即使有部分 Eureka Server 出现故障,其他的 Eureka Server 依然可以继续工作。
例如,在一个包含多个 Eureka Server 的数据中心中,如果一台 Eureka Server 因为硬件故障或者网络问题无法工作,剩余的 Eureka Server 能够接手其工作,继续为服务提供者和消费者提供注册和发现服务,不会因为某个节点的故障而导致整个系统无法运行。
另外,在分布式环境中,网络可能会出现波动或者短暂的故障, Eureka 有一个重要的自我保护机制。
当 Eureka Server 在短时间内丢失大量的心跳连接(例如,由于网络抖动,很多客户端与服务端之间的心跳连接中断),它 不会立即清除这些看起来已经 "死掉" 的服务实例。而是进入自我保护状态,在这个状态下,Eureka Server 仍然会对外提供服务,包括已有的注册信息。
这就保证了在网络不稳定的情况下,Eureka Client 服务消费者仍然能够获取到可能还在正常运行的服务实例信息,尽可能地维持服务的可用性。
再 看看 Eureka 分区容错性(P)
在面对网络分区的情况时,Eureka 更侧重于保证可用性。
例如,当网络分区导致部分 Eureka Server 和服务实例之间无法通信时,Eureka 会允许每个分区继续工作。
每个分区内的服务实例可以在自己所属的分区内进行注册和发现服务。
这样就避免了因为网络分区而导致整个系统无法使用,体现了良好的分区容错性。
不过,这种情况下可能会出现数据不一致的情况,例如不同分区对于服务实例的状态(如是否可用)可能有不同的认知,但这是为了优先保证系统的可用性和分区容错性所做出的权衡。
最后,看看 Eureka 的一致性(C)的权衡
Eureka 没有采用强一致性模型。
在服务注册和发现的过程中,Eureka 更关注服务的可用性。Eureka 允许在一定时间内不同 Eureka Server 之间的数据存在差异。
例如,当一个服务实例刚刚注册到一个 Eureka Server 时,其他 Eureka Server 不会立即获取到这个信息,
例如,当一个服务实例状态发生改变(如从可用变为不可用),这个信息在所有 Eureka Server 中同步可能会有延迟。
牺牲数据的一致性,就是因为CAP定理来的,是为了提高系统的整体性能和可用性,使得 Eureka 更符合 AP 系统的特点。
CP 组件(Consistency and Partition Tolerance)
zookeeper 是 CP 型
首先 分析一下 zookeeper 的 分区容错性(P)
当网络分区发生时,例如部分节点之间无法通信,Zookeeper 集群会尝试重新建立连接。
如果分区情况,会通过 过半机制,形成多数派+ 少数派,然后放弃少数派。
例如,一个集群有 5 个节点,因为分区变成了两个子集群,一个子集群有 2 个节点(多数派),另一个有 3 个节点(多数派),那么:
(多数派)3 个节点的子集群可以继续工作 ,
少数派2 个节点 会暂停服务,以避免数据不一致。
这样做虽然会牺牲部分节点的可用性,但保证了整个集群的一致性和分区容错性。
再 来分析一下 zookeeper 的 可用性(A)
Zookeeper 为了确保一致性,在一定程度上牺牲了可用性。
在网络分区或者节点故障导致无法形成多数派的情况下,少数派节点会被隔离,不能提供服务。
例如,如果一个集群有 3 个节点,当一个节点故障,剩下两个节点还可以继续工作;
但如果出现网络分区,将 3 个节点分成两个单独的部分(如 1 个节点一组和 2 个节点一组),那么只有 2 个节点的那一组可以工作,1 个节点的那一组会停止服务,直到网络分区恢复或者节点重新加入多数派。
这种设计使得 Zookeeper 更侧重于一致性和分区容错性,符合 CP 系统的特点。
最后 分析一下 zookeeper 的 一致性(C)
Zookeeper 使用 ZAB(Zookeeper Atomic Broadcast)协议来保证一致性。
在 ZAB 协议中,当一个事务(如节点数据的更新)被提议时,它会通过一个类似于两阶段提交的过程在集群中传播。
首先是广播阶段,主节点(leader)会将事务提议发送给所有的从节点(follower)。
然后是提交阶段,当多数从节点都成功接收并持久化这个提议后,主节点才会提交这个事务,并且通知所有从节点也提交,这样就确保了所有节点要么都执行这个事务,要么都不执行,从而保证了数据的一致性。
两阶段的 事务, 意味着网络上 有很多次 IO 通讯,这是是低性能的。
总之 :zookeeper 是 cp 型。
MongoDB 属于 CP
MongoDB 是一个流行的 NoSQL 数据库管理系统,它将数据存储为 BSON(binary JSON)文档。
MongoDB 是一个单一的主系统,每个副本集只能有一个主节点来接收所有的写操作。
同一副本集中的所有其他节点都是辅助节点,它们复制主节点的操作日志并将其应用于自己的数据集。
默认情况下,客户机也从主节点读取数据,但他们也可以指定一个允许他们从辅助节点读取数据的读取首选项。
当主节点不可用时,具有最新操作日志的次节点将被选为新的主节点。
一旦所有其他次要节点都赶上新的主节点,集群将再次可用。由于在此期间客户端无法发出任何写请求,因此数据在整个网络中保持一致。
相对于 CAP 定理,MongoDB是一个 CP 数据存储,它通过保持一致性来解决网络分区问题,同时降低可用性。
Apache HBase 属于 CP
- HBase 是一个分布式、面向列的数据库,基于 Hadoop HDFS 构建,具有高可用性、强一致性和分区容忍性。
Nacos 属于 AP 又 AP?
Nacos 属于 AP 又 AP ? 在这个问题前我们先看一下Nacos的节点
client 永久节点
- 当client节点注册在 Nacos 时, 设置ephemeral = false时,注册的节点为永久节点。
- 与临时节点不同,永久节点的信息会一直保存在 Nacos 的服务注册表中,除非通过明确的删除操作,否则不会因为服务实例的健康状态变化而自动移除。
这意味着即使服务实例出现故障(如网络中断、进程崩溃等),其在 Nacos 中的注册信息依然存在。
client 临时节点
在 Nacos 中,当client节点注册时设置ephemeral = true,表示该节点是一个临时节点。
- 临时节点主要用于服务发现场景下的临时服务实例注册。
- 临时节点 与永久节点(ephemeral = false)相对,临时节点的生命周期与服务实例的健康状态直接相关。
- 如果服务实例出现故障(如网络中断、进程崩溃等),Nacos 会自动将该临时节点从服务列表中删除。
- 默认的微服务实例, 是 client 临时节点Nacos 支持 CP+AP 模式, 其实和 CAP 不冲突。
- Nacos 支持 CP+AP 模式,这意味着 Nacos 可以根据配置识别为 CP 模式或 AP 模式,默认情况下为 AP 模式。
临时节点 AP:如果注册Nacos的client节点注册时ephemeral=true,那么Nacos集群对这个client节点的 状态维护使用 AP模式,采用distro协议实现;
永久节点 CP:而注册Nacos的client节点注册时ephemeral=false,那么Nacos集群对这个节点的状态维护使用 CP模式,采用raft协议实现。
根据client注册时的属性,AP,CP只能二选一 ,只是对不同的client节点效果不同.
总之, 同一个 节点, 要么CP、要么AP,只能二选一 。
因此,Nacos 能够很好地满足不同场景的业务需求。