CAP理论
概述
分布式系统最大的难点, 就是各个节点的状态如何保持一致, CAP理论是在设计分布式系统的过程中, 处理数据一致性问题时必须考虑的理论.
CAP理论的本质很简单, 它就是一种分布式系统设计的不同理念概括.
CAP理论说, 一个分布式系统, 不能同时满足以下三个特性:
- 一致性(Consistency): 对于客户端的每次读操作, 要么读到最新数据, 要么读取失败, 强调数据正确
- 可用性(Availability): 任何客户端的请求都能得到返回数据, 不会出现失败(返回时间必须合理, 过长也不行), 不保证数据最新, 但强调不出错
- 分区容忍性(Partition tolerance): 当发生网络分区时, 系统能正常运行
网络分区: 一个分布式系统里, 节点组成的网络本来是连通的, 然而可能因为一些网络或设备故障, 使得有些节点之间不连通了, 整个网络就分成了几块区域,
数据就散布在这些不连通的区域中, 这就叫分区
对分布式系统而言, P是前提必须保证, 因为只要有网络交互, 分区错误是必然发生的, 所以只能考虑当发生分区错误时, 如何选择一致性和可用性.
而根据选择不同, 开源的分布式系统往往被分为CP系统和AP系统
- 当一套系统发生分区故障后, 客户端的请求会被卡死或者超时, 但系统每个节点总是返回一致的数据, 那么这套系统就是CP系统, 例如Zookeeper
- 当一套系统发生分区故障后, 客户端依然能访问系统, 但获取的数据有新有旧, 那么这套系统就是AP系统, 例如Eureka
注意
有两点容易存在误区
- CAP理论并非是在所有时候都只能选择两个特性, 分区错误发生概率很低, 在不存在网络失败情况下, c和a是能同时保证的, 只有当网络发生分区或失败时, 才会在c和a之间做出选择
- 对C和A的选择不必是针对整个系统的, 可以对不同子系统有不同的抉择
CAP的不足
- CAP理论本身是没有考虑网络延迟问题的, 它认为一致性是立即生效的, 但是要保持一致性, 是需要时间成本的
- 实践中一致性和可用性并不仅仅是二选一的关系, 只是一些重要性的区别, 往往选择一方的同时, 也会采用一些技术手段去保证另一项
- CAP理论只是一种对状态的描述, 但对状态间如何转换, 如何修补, 如何恢复并没有提供方向
针对CAP的不足, 延伸出了BASE理论, 弥补了CAP理论过于抽象的问题
BASE理论
理论
BASE理论是一种处理分布式事务的思想, 没有具体的操作步骤, 要理解BASE理论需要结合具体的例子.
BASE理论是对CAP中一致性和可用性权衡的结果, 来源于对大规模互联网分布式系统实践的总结, 基于CAP理论演化而来
核心思想是即使无法做到强一致性, 但每个应用都可以根据自身业务特点, 采用适当的方式来使系统达到最终一致性.
实际上, 网络分区出现情况很少, CAP在大多时间能够同时满足C和A, 对于分区错误出现的情况下, 需要提供一种预备策略做处理:
- 探知网络分区的发生
- 进入显式的分区模式, 限制某些操作
- 启动恢复过程, 恢复数据一致性, 补偿分区发生期间的错误
定义
BASE理论核心
- Basically Available(基本可用)
出现了不可预知的故障, 但还能用, 相比较正常的系统, 可能有响应上的损失或者功能上的损失
在架构设计中, 把以前可能影响全平台的严重问题, 变成只会影响平台的一部分数据或者功能的非严重问题 - Soft State(软状态)
允许系统中的数据存在中间状态, 并认为该状态不影响系统的整体可用性, 即允许系统在多个不同节点的数据副本存在数据延时
对实时性不高的数据可以延后处理 - Eventually Consistent(最终一致性)
软状态不能一直持续, 在一定时间期限过后, 应当保证所有副本保持数据一致性, 从而达到最终一致性, 这个时间期限取决于网络延时, 系统负载, 数据复制方案等等因素
对于不符合业务需求的软状态, 通过一些后续内部的自动化操作把数据状态补充完整从而最终满足业务需求.
总体来说BASE理论面向的是大型高可用, 可扩展的分布式系统, 与传统ACID特性相反, 不同于ACID的强一致性模型, BASE提出通过牺牲强一致性来获得可用性
并允许数据段时间内的不一致, 但是最终达到一致状态.
ACID
Atomicity(原子性): 不管事务里执行多少命令, 对外它们是一体的, 要么都执行, 要么都不执行
Consistency(一致性): 事务执行前后, 数据从一个状态到另一个状态必须是一致的
Isolation(隔离性): 多个并发事务之间相互隔离,不能互相干扰
Durability(持久性): 事务完成后,对数据库的更改是永久保存的,不能回滚
2PC
两阶段提交协议, 又称2PC(two-phase commit protocol), X/Open XA协议的经典实现, 是一个非常经典的强一致, 中心化的原子提交协议
协议中有两类节点, 一个中心化协调者节点(cordinator)和N个参与者节点(partcipant)
两阶段提交是指, 整个过程中存在两个阶段的处理流程
- 第一阶段, 请求阶段
当分布式事务的发起方向协调者发送请求时, 协调者分别向参与者发送事务预处理请求, 称之为Prepare
参与者开始执行本地事务, 但执行完成后并不提交事务, 而是先向协调者报告自己能否执行成功
当所有参与者都向协调者做出反馈, 此时流程进入第二阶段 - 第二阶段, 提交阶段
如果所有参与者都报告能执行成功, 那么协调者会向所有参与者发送Commit请求, 参与者就会完成自身事务的提交, 并将最终提交结果回复给协调者, 协调者再向调用方返回分布式事务处理完成的结果
–
相反如果有参与者报告执行会失败, 此时协调者就会向所有参与者发送Rollback请求, 参与者回滚本地事务释放资源, 并向协调者发送ack消息, 协调者再向调用方返回分布式事务处理失败的结果
但2PC也存在一些问题:
- 性能问题, 在1,2阶段的执行过程中, 所有参与者的事务操作都是处于阻塞状态
- 单点故障, 协调者是单点, 如果协调者出现问题, 整个流程就会锁住无法执行, 参与者也没有超时机制
- 数据不一致, 二阶段协调者向参与者发送提交通知, 如果网络抖动, 部分参与者收到了部分参与者没收到, 则会出现数据不一致现象
3PC
三阶段提交协议, 是2PC的改进版, 将请求阶段一分为二, 变成canCommit, preCommit和doCommit三个阶段组成的事务处理协议, 并且引入了超时机制
- 第一阶段 canCommit
协调者向所有参与者发送canCommit请求, 询问是否可以执行事务提交操作, 然后开始等待参与者响应
参与者收到请求后, 检查自身状态及资源, 确认可以顺利执行事务则返回yes, 否则返回no - 第二阶段 preCommit
如果所有参与者反馈yes, 则协调者向参与者发送preCommit请求, 参与者收到请求, 执行事务操作, 但不提交事务, 如果参与者成功执行了事务, 则返回ack确认响应, 同时等待最终命令
–
如果有参与者反馈no或者等待超时, 协调者向所有参与者发送abort请求或参与者超时未收到协调者请求, 参与者执行事务中断 - 第三阶段 doCommit
协调者收到参与者发送的ack响应后
如果参与者都能执行成功, 向所有参与者发送doCommit请求, 参与者收到请求后, 执行正式的事务提交, 并在完成之后释放事务资源, 向协调者发送ack响应, 协调者收到所有ack后完成事务
–
当有参与者在二阶段未完成反馈或者反馈超时, 则协调者向所有参与者发送abort请求, 参与者收到请求后, 回滚事务, 并释放所有事务的资源, 然后向协调者发送ack响应, 协调者收到所有ack后, 执行事务的中断
但3PC依旧存在单点故障和数据不一致问题