CAP 三选二公式误导性
理解 CAP
处理策略
CAP 和延迟的联系
理解 CAP
想象两个节点分处分区两侧
允许至少一个节点更新状态会导致数据不一致,即丧失 C 性质
如果为了保证数据一致性,将分区一侧的节点设置为不可用,又丧失了 A 性质
除非两个节点可以互相通信,才能既保证 C 又保证 A,又会导致丧失 P 性质
一般来说跨区域的系统,设计师无法舍弃 P 性质,只能在C和A做一个艰难选择
NoSQL 运动主题是创造各种A优先、C其次的方案;传统数据库坚守 ACID 特性,做的是相反的事情
再理解 CAP
但凡知道点分布式的人都对 CAP 理论耳熟能详,但真正要解释给别人时却总是难以自圆其说,像是一千个人眼中有一千个哈姆雷特
C 容易理解,所有节点上的数据都一样
P 是说一旦集群因为内部通信故障发生分裂,集群还能正常运转
关键是这个 A
咋一看 Availability 简直太好理解了,通常指系统能正常工作,系统架构所追求的 HA 即保证系统高可用,不宕机。企业级的 4 个 9,5 个 9 的,说的就是这个 A
但 CAP 理论里这个 A 却不是这个意思,《NoSQL Distilled》 里对这个问题专门做了澄清:
说白了就是 CAP 里的 A ,只要是活着的节点能返回响应,那么就认为它是 availability 的
用汽车来做个比喻:
汽车一切良好,故障灯一个都不亮,能开能刹,这是我们理解的传统 Available
车胎爆了,发动机坏了,或者是没油开不动了,这都已经是不可用了
CAP 理论里,车不能开不要紧,只要是这车车门还能打开,那就是 Available 的
车胎破了能从胎压监测里看到,发动机坏了打火打不着,没油了油表灯会亮…… 这都是车返回的 response
只要是有 response,那么就是” 可用的
只满足 CA 的系统
P 定义: 集群因为内部通信故障发生分裂,集群还能正常运转。 舍弃 P 意味着一旦集群发生分裂,整个集群都将无法运转。这是符合 A 的,因为这是的节点是 fail 的,不需要给任何响应
单机服务器显然是 CA 的,只要结点活着,那自然是 C+A
而结点一旦挂了,整个集群也就没了,符合舍弃 P 的选择
只满足 CP 的系统
一旦集群内部因为内部通信故障发生分裂(假设分裂成两部分),为了满足 P,集群需要提供服务
而为了满足 C,只能保留其中一部分提供服务,让另一部分整体退役
只满足 AP 的系统
最容易理解,一旦集群内部因为内部通信故障发生分裂(假设分裂成两部分),为了满足 P,而又不需要满足 C,那么可以让分裂出来的两部分都提供服务,因为暂时数据不一致没关系
CAP 三选二公式误导性
CAP 理论断言任何基于网络的数据共享系统,最多只能满足数据一致性、可用性、分区容忍性三要素中的两个要素
三选二公式过分简单化各性质之间的相互关系,在分区存在的前提下呈现完美的数据一致性和可用性 这种很少见的情况是 CAP 理论不允许出现的
处理策略
分区很少发生,不存在分区的情况下没什么理由牺牲 C 或 A
C 与 A 之间的取舍可以在同一系统内以非常细小的粒度反复发生,每一次决策可能因为具体的操作,乃至因为牵涉到特定的数据或用户而有所不同
三种性质都可以在程度上衡量,不是非黑即白的有或无
可用性在 0% 到 100% 连续变化
一致性分很多级别
分区也可以细分为不同含义
- 探知分区发生
- 进入显式的分区模式以限制某些操作
- 启动恢复过程以恢复数据一致性并补偿分区期间发生的错误
CAP 和延迟的联系
CAP 理论的经典解释,是忽略网络延迟的,但实际延迟和分区紧密相关
CAP 从理论变为现实的场景发生在操作的间歇,系统需要在这段时间内做出关于分区的一个重要决定:
- 取消操作因而降低系统的可用性,还是
- 继续操作,以冒险损失系统一致性为代价
依靠多次尝试通信的方法来达到一致性,比如 Paxos 算法或者两阶段事务提交,仅仅是推迟了决策的时间
系统终究要做一个决定;无限期地尝试下去,本身就是选择一致性牺牲可用性的表现
实际效果而言,分区相当于对通信的时限要求
系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择
这就从延迟的角度抓住了设计的核心问题:分区两侧是否在无通信的情况下继续其操作?
重要推论
第一,分区并不是全体节点的一致见解,有些节点检测到了分区,有些可能没有
第二,检测到分区的节点即进入分区模式——这是优化 C 和 A 的核心环节
这个观察角度意味着设计师可以根据期望中的响应时间,有意识地设置时限;时限设得越短,系统进入分区模式越频繁,其中有些时候并不一定真的发生了分区的情况,可能只是网络变慢而已
系统进入到分区模式,有两种可行的策略
其一是限制部分操作,削弱可用性
其二是额外记录一些有利于后面分区恢复的操作信息。系统可通过持续尝试恢复通信来察觉分区何时结束