分布式系统中的CAP理论与事务

 

当把单体服务按功能领域拆分成多个微服务模块,每个模块为高可用又做多个副本部署,一个完整的事务流程就需要多个微服务组合完成。分布式系统的核心问题,就是各个节点的状态如何同步。CAP定理就是对这个问题的理论描述。

1998年,Eric Brewer 提出,分布式系统有C、A、P三个关键指标,并且不能同时满足。

  • Consistency:一致性
  • Availability:可用性
  • Partition tolerance:分区容错性

CAP

Partition tolerance

分区容错性是分布式系统的一个关键特性,是系统遇到网络故障导致分区(即系统内的节点间通信因网络故障而被部分或完全切断)时,仍然能够继续服务的能力。由于网络本身的不稳定性,网络分区是一种可能出现的常态而非异常情况,分布式系统应当在这种不利条件下依然能够提供一定程度的服务,即使这种服务可能是降级的。

上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。

一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。

Consistency

同样以上图为例,client 向 $G1$ 发起一个写操作,将 $v0$改为 $v1$,接下来,从 $G1$ 读操作得到 $v1$,叫一致性。
问题是,如果读操作是读自$G2$,由于$G2$的值没有发生变化,因此返回的是 $v0$。$G1$ 和 $G2$ 读操作的结果不一致,这就不满足一致性了。
为了让 $G2$ 也能变为 $v1$,就要在 $G1$ 写操作的时候,让 $G1$ 向 $G2$ 发送一条消息,要求 $G2$ 也改成 $v1$。这样向 $G2$ 发起的读操作,也能得到 $v1$。

Availability

意思是只要收到用户的请求,服务器就必须给出回应。

用户可以选择向 $G1$ 或 $G2$ 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 $v0$ 还是 $v1$,否则就不满足可用性。

Consistency 和 Availability 的矛盾

如果保证 $G2$ 的一致性,那么 $G1$ 必须在写操作时,锁定 $G2$ 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,$G2$ 不能读写,没有可用性。

如果保证 $G2$ 的可用性,那么势必不能锁定 $G2$,所以一致性不成立。

所以,$G2$ 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

事务

多个操作作为一个整体进行操作,被称为事务。事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。

事务具有如下4个属性,通常称为ACID特性。

  • Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会回滚到初始状态。
  • Consistency(一致性):在事务开始前、进行中、结束后,数据库的完整性没有被破坏。完整性包括外键约束、应用定义的等约束不会被破坏。
  • Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  • Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

假如业务系统不复杂,可以在一个数据库、一个服务内对数据进行修改,完成业务流程,那么,我们可以利用数据库事务,保证业务的正确完成。

分布式事务

分布式事务就是指事务的发起者、资源及资源管理器和事务协调者分别位于分布式系统的不同节点之上。分布式事务就是为了保证在分布式场景下,数据操作的正确执行。

分布式事务会部分遵循 ACID 规范:

  • 原子性:严格遵循
  • 一致性:事务完成后的一致性严格遵循;事务中的一致性可适当放宽
  • 隔离性:并行事务间不可影响;事务中间结果可见性允许安全放宽
  • 持久性:严格遵循

因为事务过程中,不是一致的,但事务会最终完成,最终达到一致,所以我们把分布式事务称为“最终一致”。

最终一致性释疑

特别强调一下,这里的最终一致性和CAP的最终一致性不同,目前大部分的书籍和资料,都将两者混为一谈,下面我们将重点进行一致性的解释。

CAP的C指的是分布式系统中从多副本读取数据时的一致性。简单的说,如果我将一个数据从v0更新为v1,之后任意的数据读取:

  • 强一致:每次都能确保读到v1,那么是强一致
  • 弱一致:可能读到v0,也可能读到v1,那么是弱一致
  • 最终一致:经过一定时间后,确保每次读取能够读到v1,那么是最终一致

CAP理论提出,分布式系统无法同时满足3个特性,最多只能选2,面对这样的问题,有一类经典的方案是BASE理论,这类方案追求AP,然后放宽对C的要求。

BASE

BASE是Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写。

系统层面放弃对于C的苛刻要求,允许数据存在中间状态,并认为该状态不影响系统的整体可用性, 即允许系统在多个不同节点的数据副本存在数据延迟。但会尽可能保证在某个时间级别(比如秒级别)之后,可以让数据达到一致性状态。

BASE理论面向的是大型高可用可扩展的分布式系统,和传统事务的ACID特性使相反的,它完全不同于ACID的强一致性模型,而是提出通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID特性与BASE理论往往又会结合在一起使用。

CP+HA

近些年分布式理论进一步发展,有很多系统不走BASE方案,而是CP+HA(Highly-Available)的方案。Paxos、Raft等分布式共识协议,完全满足CP,而在A-可用性上面,虽然不是100%的可用,但是结合近些年硬件稳定性升级,可以做到了高可用。谷歌分布式锁Chubby的公开数据显示,集群能提供99.99958%的平均可用性,一年也就130s的运行中断,已经能够满足非常严苛的应用要求。现在的SQL类数据库软件,都是走CP+HA,只是HA会比谷歌的这个极致数据更低一些,但一般都能够达到4个9

CP+HA意味着不是BASE,意味着你只要写入成功,那么接下来的读,能够读取到最新的结果,开发人员不用担心读取到的不是最新数据,在多副本读写上面,与单机是一致的。

因为分布式事务研究解决的主要是涉及多数据库的数据一致性,实际数据的存储主要在数据库,因此也是CP+HA。因此分布式事务满足CAP的C,但是不满足ACID的C,也被称为最终一致。


参考:

  • https://www.cnblogs.com/incognitor/p/9759956.html
  • https://berb.github.io/diploma-thesis/community/061_challenge.html
  • https://segmentfault.com/a/1190000040321750