ACID/CAP/Base理论
传统关系数据库中事务的ACID特性
分布式系统中的经典理论——CAP定理和BASE理论
分布式实际上就是单一的本地一体解决方案,在硬件或者资源上不够业务需求,而采取的一种分散式多节点,可以扩容资源的一种解决思路。它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给多个计算机进行处理,最后把这些计算结果综合起来得到最终的结果。
ACID理论
事务
事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元(Unit),狭义上的事务特指数据库事务
。
事务的作用
- 当多个应用程序并发访问数据库时,事务可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作相互干扰。
- 事务为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持数据一致性的方法。
ACID
事务是基于数据进行操作,需要保证事务的数据通常存储在数据库中。
一个良好的事务处理系统,必须具备四个标准特性,即ACID。
- 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,不可能停滞在中间某个环节,对于一个事务来说,不可能只执行其中的一部分操作。
- 一致性(Consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。
- 隔离性(Isolation):通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的(在并发环境中,并发的事务是相互隔离的,事务之间互不干扰)。
- 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- 针对不同的业务需求,隔离性分为4个级别:读未提交、读已提交、可重复读、串行化。
隔离级别 | 脏读(Dirty Read) | 可重复读(Nonrepeatble Read) | 幻读(Phantom Read) |
---|---|---|---|
读未提交(Read Uncommitted) | 存在 | 不可以 | 存在 |
读已提交(Read Committed) | 不存在 | 不可以 | 存在 |
可重复读(Repeatable Read) | 不存在 | 可以 | 存在 |
串行化(Serializable) | 不存在 | 可以 | 不存在 |
以上4个级别的隔离性依次增强。事务隔离级别越高,就越能保证数据的完整性和一致性,但同时对并发性能的影响也越大。
- 持久性(Durability):通常来说,一旦事务提交,则其所做的修改会永久保存到数据库(即使系统崩溃,修改的数据也不会丢失)。
隔离性的4个级别
- 读未提交是数据库应保证的最低的隔离性级别:事务中的修改,即使没有提交,对其他事务也都是可见的。
- 面临脏读问题:事务可以读取未提交的数据,而该数据可能在未来因回滚而消失。
- 读已提交满足前面提到的隔离性的简单定义:一个事务所做的修改在最终提交以前,对其他事务是不可见的。换句话说,一旦提交,该事务所作的修改对其他正在进行中的事务就是可见的。
- 解决了脏读问题,但面临不可重复读的问题:两次执行同样的查询,如果第二次读到了其他事务提交的结果,则会得到不一样的结果。
- 大多数数据库的默认隔离级别都是读已提交,但MySQL不是。
- 可重复读解决了部分不可重复的问题:同一个事务中多次读取同样记录结果是一致的。记录指具体的数据行。
- 面临幻读问题:当某个事务在读取目标范围内的记录时,另一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生第一次读取范围时不存在的幻行(Phantom Row)。需要注意的是,只有插入会产生幻行。
- MySQL的默认隔离级别是可重复读,有幻读问题。
- 可序列化是最高的隔离级别:强制事务序列化执行。
- 解决了幻读问题。简单来说,可序列化会在目标范围加独占锁,将并发读写相同范围数据的请求序列化。可序列化会导致大量的超时和锁争用问题。
不可重复读与脏读之间存在交叉。脏读侧重读到不应存在的数据,不可重复读强调两次相同查询的结果不一样。
实际上,可以将描述放宽到“目标记录的状态不符合预期状态”,如本应该不同,却读到了相同。本质上也是由于读已提交实现原理导致的问题。
MySQL的默认隔离级别是可重复读,解决了脏读、部分不可重复读问题,有幻读问题。
CAP理论
CAP定理:一个分布式系统不可能同时满足一致性(Consistence)
、可用性(Availability)
和分区容错性(Partition tolerance)
这三个基本要求,最多只能满足其中的两项。
- 一致性:所有节点在同一时间的看到的数据相同(数据在多个副本之间是否能够保持一致的特性)。
- 一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意结点读取到的数据都是最新的状态。
- 可用性:读、写永远都能成功,即,服务一直可用(系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果,如果超过了这个时间范围,那么系统就被认为是不可用的)。
- 所有请求都有响应,且不会出现响应超时或响应错误。
- 分区容错性:即使系统的某个分区遇到严重的故障,系统能继续提供服务。
CAP中的权衡
- CA:这样的系统关注一致性和可用性,它需要非常严格的全体一致性协议,比如上文提到的”两段提交”(2PC)。CA 系统不能容忍网络错误或者节点错误,一旦出现这样的问题,整个系统就会拒绝写请求,因为它并不知道是对面的那个节点宕机还是网络错误。唯一安全的做法就是把自己变成只读的。
- CP:这样的系统关注一致性和分区容错性。它关注的是系统里大多数人的一致性协议,比如:Paxos 算法 (Quorum 类的算法)。这样的系统只需要保证大多数节点数据一直,而少数的节点会在没有同步到最新版数据时编程不可用的状态。这样能够提供一部分的可用性。
- AP:这样的系统关心可用性和分区容错性。因此,这样的系统不能达成一致性,需要给出数据冲突,给出数据冲突就需要维护数据版本(Dynamo)。
对于多数大型互联网应用的场景:主流做法是首要保障P、在A和C之间取舍、重A轻C。
对于金融服务:必须保证C;为了保证C、P,只能牺牲A(停止服务)。
对于某些特殊的金融服务,需要7*24小时提供服务,则需牺牲部分P,保证C、A。
CAP的误解
- P是必选项吗?
- 分区不会频繁出现,但是一定会出现。因此分布式系统的分区容忍性是必选项。
- 在满足分区容错的前提下,没有算法能同时满足数据一致性和服务可用性。
- 分区不会频繁出现,但是一定会出现。因此分布式系统的分区容忍性是必选项。
- CA一定要二选一吗?
- CAP定理证明中的一致性指线性一致性,即强一致性。
- 强一致性要求多节点组成的被调要能像单节点一样运作、操作具备原子性,数据在时间、时序上都有要求。
- 可用性在 CAP 定理里指所有读写操作必须要能终止,实际应用中从主调、被调两个不同的视角,可用性具有不同的含义。当网络分区出现时,主调可以只支持读操作,通过牺牲部分可用性达成数据一致。
- CAP定理证明中的一致性指线性一致性,即强一致性。
序列一致性(sequential consistency):不要求时序一致,A 操作先于 B 操作,在 B 操作后如果所有调用端读操作得到 A 操作的结果,满足序列一致性;
最终一致性(eventual consistency):放宽对时间的要求,在被调完成操作响应后的某个时间点,被调多个节点的数据最终达成一致。
Base理论
BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结。
BASE是基于CAP逐步演化而来的:即使无法做到强一致性(Strong Consistency),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。
CAP中提到的一致性是强一致性,所谓“牺牲一致性”指牺牲强一致性保证弱一致性。
ACID
是传统数据库常用的设计理念,追求强一致性模型。
BASE
支持的是大型(高可用可扩展的)分布式系统,提出通过牺牲强一致性获得高可用性。
BASE是指基本可用(Basically Available)
、软状态(Soft State)
、最终一致性(Eventual Consistency)
。
- 基本可用:系统在出现不可预知故障的时候,允许损失部分可用性,即,保证核心可用。
- 响应时间上的损失
- 功能上的损失(降级页面)
- 软状态:允许系统存在中间状态,而该中间状态不会影响系统整体可用性,即允许系统在多个不同节点额度数据副本存在数据延迟。
- 软状态本质上是一种弱一致性,允许的软状态不能违背“基本可用”的要求。
- 原子性(硬状态):要求多个节点的数据副本都是一致的,这是一种“硬状态”。
- 所有节点的数据必须完全一致之后,才能对外正常服务提供数据。
- 最终一致性:系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。
- 软状态的终极目标是最终一致性。如,分布式存储的副本数最终会达到稳定状态。
参考文章
分布式系列文章——从ACID到CAP/BASE
分布式理论:CAP、BASE与ACID
事务的ACID和四个隔离级别
谈谈 ACID、CAP 和 BASE
分布式从ACID、CAP、BASE的理论推进