微服务架构下的分布式事务

系统软件为了实现一定的业务,会将现实中的人、事、物进行抽象表示,并将其映射为系统中的模型。

业务模型大致可以按以下来构建:
1、定义系统中应该存在哪些实体、实体上有哪些属性。
2、定义实体之间的各种拓扑关系,如从属、嵌套、多对多。
3、定义实体和属性的动态关系,即定义系统流程

第1、2步是静态的,因此可以用E-R图(实体-关系图)来表示,它能够描述系统在某个时间节点所有可能的状态,第3步需要用流程图和“状态-转移图”来表示,它能够描述系统随着时间的推移的变化规律。

业务模型是系统中最容易发生变化的部分,体现在:
1、系统中的实体、属性种类的增减
2、实体之间拓扑关系的改变
3、系统流程变更

数据库是负责存储这些业务模型的。数据存储模型的设计就是数据库的设计,工作包括:数据存储结构、索引结构、读写控制。实体对应到表、实体的属性对应到表中的字段,遵循数据库设计范式减少冗余的表和字段。

单体应用时代通常采用单一的关系数据库,微服务时代并不再受限于单一数据库,微服务架构下,服务可以选择专精于相应领域中的数据库,如搜索引擎数据库Elasticsearch,分布式存取海量数据的MongoDB等。

软件系统为了保证业务模型上的状态的互斥完备,就要求存储模型也是互斥完备的。从数据库角度来看,就是数据库中某些表中的字段必须同时变化;从数据库客户端来看就是对数据库进行一组写入操作,要么成功,要么失败。这就是所谓的事务。

事务的特点ACID:
1、A(Atomicity)原子性,在同一组数据库操作中,其中某一步失败了,之前的所有操作都会被回滚,不允许出现部分成功,部分失败的情况。
2、C(Consistency)一致性,即数据操作符合某种业务约束。比如说A账户转钱给B账户,那么对于两个账户的钱的增减,应该符合A账户钱会减少,B账户应该增多。这就是一个比较简单转账业务逻辑。符合相应的业务逻辑就达到了一致性要求。
3、I(Isolation)隔离性,并发的数据操作要有一定的隔离性,隔离性最差的情况是并发操作没有一点隔离、互相干扰;最好的情况是并发操作等效于一系列串行操作。隔离性越高也意味着数据库需要更多的资源来实现,存取数据的吞吐量也会随之降低、延迟增加。
4、D(Durability)持久性,要求到达数据库的数据不会丢失,换据话说就是存储到了外存中,计算机停电、重启等条件都不会导致数据丢失。

分布式系统的出现,尤其是分布式数据库,相比较于单体应用和传统的数据库来说,除了要满足ACID标准事务上,分布式系统还有一个问题尚未等到解决。就是常说的CAP三选二定理。

1、C(Consistency):一致性,就是说分布式系统的任何节点对同一个Key的读写请求的结果都是完全一致的。
2、A(Availability):可用性,就是每次请求都能够得到及时并正常的响应,但是不保证数据是最新的。
3、P(Partition tolerance)分区容错性,节点不能连通时,不能保持正常的运转。

这三个特性不能同时满足,只能满足其中两个。

有人是这么说的,因为P分区容错性通常是无法避免的既定事实,如果不存在网络分隔,又或者说不要求在出网络隔离时,仍然要正常提供服务,那么对于这种情况完全可以放弃分布式架构,直接用集中心架构来做就可以。所以现在变成了,接受P,在C和A之间根据业务需要进行选择。
1、选择C一致性,放弃A可用性,就是要强一致性,低可用性。在这类系统中,写入数据库的请求只在提交并且同步到所有的数据库节点后才会返回响应,任意一个节点出现故障都会导致服务整体不可用,直至故障修复。账务金融领域的系统通常会采用这种架构。
2、选择A可用性,放弃C一致性,就是要高可用,最终一致性。在这类系统中,写入数据库的请求只要在部分数据库节点上成功提交即可立即返回响应,不需要等到数据同步到所有数据库节点才返回。使用这样的架构可以提供服务的可用率,只有要少数据存活的服务节点,服务就可用。坏处是写入数据请求完成后的一段时间(无上限)内,读取同一条数据的结果可能会有一定的概率是错误的,这种数据约束称为BASE(Basically Available Soft state Eventually consistent)。
(1)基本可用:通过使用分布式数据库,尽可能使用读写操作处于可用的状态,但不保证数据的一致性,如数据可能没有被持久化、或读回的数据不是最新的。
(2)软状态:即某条数据在写入后一段时间内的状态是未知的,在最终收敛之前,系统有一定概率会返回最新的值。
(3)最终一致性:在系统功能正常的前提下,等待足够长的时间之后,某条数据在系统中的状态能够收敛达成一致,之后,读取到的数据都是最新的。

如果分布式系统如果采用了分布式甚至是异构的数据存储方案,那么在写顺序方向可能会遇到问题: 同一条数据在不同服务上并发写入时,可能会因为写入顺序不同而导致写入的数据不一致。这种问题并不一定违反了BASE或ACID约束,但前业务模型的角度来看,这不是预期的结果,系统不能正确反映业务模型。比如说现在A、B、C三个服务各自使用了不同的数据库,现在有两个请求1和请求2,并发修改同一个数据项,这个数据项分别由这三个服务进行处理,由于网络延迟,这个数据项在三个数据库中的值可能会不一致,如在A中为100,在C中为200.

现在业界已有一些分布式事件框架方案:
1、XA标准和二阶段提交协议
XA标准(eXtended Architecture 扩展后的架构)这个标准目的是尝试提供一套分布式事务的处理的标准。它描述了全局的事务管理与局部的资源管理器之间的接口。通过这套接口,应用可以在同一事务中跨越多个服务访问多个资源(如数据库、队列、服务)。这个标准使用了两阶段提交协议(two-phase commit,2PC)来保证所有资源同时提交或回滚任何特定的事务。

两阶段提交协议引入协调者角色,它负责统一掌握所有数据存储节点(参与者)的操作结果:
第一阶段:参与者并发进行数据操作,将结果是否成功通知协调者;
第二阶段:协调者根据所有参与者的反馈,决定是确认提交还是中止操作,并将这个决定告知所有参与者。

XA标准和二阶段提交协议的好处是:强一致性,实现数据在多个数据库上的ACID约束;业务侵入性也小,完全依赖各个数据库本身劫持实现分布式事务,不需要修改业务逻辑。坏处是:数据库的选型受限,只能选择支持XA标准的数据库;其次就是单点故障降低可用性,所有节点都不能出错;支持XA标准的数据库在设计上有大量的阻塞和资源占位,数据体量和吞吐量扩展性差。

总结来说XA标准和二阶段提交协议是强一致性,低可用性的方案,正好是金融行业常用的架构。

2、Saga分布式事务框架
它的思路是借助驱动流程机制,按顺序执行每个数据操作步骤。一旦出错,就倒序执行之前各步骤对应的“补偿”操作。所以Saga要求每个步骤涉及的服务都要提供正向操作接口和对应的补偿操作接口。
Saga框架通过对一些基础服务进行组合/编排来完成各种业务需求,比较灵活,对数据库也没有什么特别的要求,甚至不要数据库。它只满足了ACID中的A和C。需要服务实现数据补偿的操作,这工作会增加开发和维护的成本。

Saga目前有Saga Orchestration 和Choreography两种实现。

3、ACID事务链的分布式事务框架

ACID事务链要求参与分布式事务的所有服务都要使用支持ACID事务的数据库,在每个服务内部,都将数据操作和同步调用相邻服务的操作打包到一个ACID事件中,通过ACID事务的链式调用来实现分布式事务。它的优点相当明显就是支持ACID。回滚的操作由支持ACID数据库执行。缺点也明显数据库选型受限,服务耦合过多,服务之间的依赖是链式拓扑,非常不方便调整,如果出现服务之间的循环依赖,会出现很多麻烦。

你可能感兴趣的:(微服务,架构,微服务,分布式)