事务和ACID
在分布式系统中,组件越来越微服务化,要完成一个业务流程需要多个微服务的配合。在执行的过程中,某个微服务难免会出现问题,为了保证业务执行的完整性和一致性,需要至少保证下面两项中的某一项:
1、尽一切努力把整个业务流程成功执行完成。
2、如果实在满足不了第一项,则需要对整个业务流程涉及的操作进行回滚。
上面这两项其实就是数据库中事务的概念:事务里的操作要么全部成功,要么全部回滚。不能够有成功一半失败一半类似的中间状态。
传统的数据库中用ACID来保证事务的完整性和一致性,即原子性(A)、一致性(C)、隔离性(I)和持久性(D)。
1、原子性:整个事务里的所有操作要么全部成功,要么全部失败,不能够有中间状态。事务执行中如果发生了错误,需要进行回滚操作,回滚到该事务没有执行过一样的状态。
2、一致性:在事务开始前和事务结束后,系统的完整性约束没有被破坏。如某个事务修改数据库中一个表的外键,不能够在执行完事务后该数据库表的外键找不到对应的主键了。
3、隔离性:事务和事务之间的执行是隔离的,一个事务是感知不到另一个事务里的任何操作影响。
4、持久性:在事务成功执行后,该事务所做的操作被持久地保存起来。
数据库的这种ACID事务机制很好地保证了数据的完整性和一致性。但是这种设计是一种强一致性的规定,对于目前分布式系统来说可能不太适用,因为这种强一致性必然导致分布式处理性能的下降。
BASE理论
分布式系统有一个著名的CAP理论,它说的就是在分布式系统中,没有办法同时满足一致性(C),可用性(A)和分区容忍性(P),只能满足这三项中的两项。那在分布式系统中如果严格地执行数据库的ACID来保证事务,那在执行性能上就会有很大的代价,那分布式系统怎么在保证执行性能的前提下保证事务的呢,于是就出现了BASE理论。
BASE从字面的意思来看,包括以下三个部分:
1、基本可用(Base Availability)。
基本可用就意味着可以容许系统有短暂的不可用状态,只要能快速恢复就可以。
2、软状态(Soft-state)。
软状态是跟持久状态相对的,也就意味着系统可以处于一种中间状态,既不是事务执行前的状态,也不是事务成功执行后的状态,这种状态会导致系统的不一致性,但是这种不一致性是短暂的,最终是要回归到一致性的。
3、最终一致性(Eventual Consistency)。
最终一致性跟强一致性相对,也就意味着系统只要能在可接受的时间范围内达到一致性即可。
BASE理论容许系统出现短暂性的问题的,无论是短暂的不可用还是短暂的不一致状态,只要能够在一定时间范围内最终达到可用或者一致状态即可。
举个例子来说一下。前几年的手机厂商很流行饥饿营销,很多人都会在在某个特定的时间点去抢购某一部手机,整个抢购系统的瓶颈点可能在支付这一块,为了解决这个瓶颈点,很多系统允许在抢到一个手机后,在12个小时之内支付即可,订单状态变为未支付状态,系统会帮你锁定库存。如果在12个小时内支付成功了,则订单状态变为交易成功。如果在12个小时内没有支付,则订单状态变为交易失败。系统允许订单处于一种短暂的soft-state状态,这种状态是未支付状态,即不是购买前的状态,也不是订单完成后的状态。
补偿机制
既然BASE理论容许系统处于短暂的不可用和不一致的状态,那么在设计的时候怎么去保证最终的可用和一致状态呢?这就需要引入补偿机制。
现在的系统往往都微服务化了,所以要完成某一个业务流程往往涉及到很多个服务,甚至涉及很多个外部的系统,外部系统的可用性不是我们能够保证的,我们在设计实现流程时能够做的就是当在调用某个三方系统失败时,后续的流程应该怎么去设计。这就需要工作流编排的能力。工作流的编排完全是基于业务的,需要根据业务的实际情况来进行流程的转换。
举个例子来说。如果去某个地方旅游,来回机票、酒店都定好了,但是旅游地的短途交通还没有预定成功,这也不会使得我们放弃这次旅游,因为旅游地的短途交通这个事情我们确认可以解决的。这个就说明当整个业务流程中的非关键操作失败后,业务流程可以正常执行。但是如果是回程机票没有定好,那我们可能就会试着再重试去预定,如果实在预定不到,那我们就会取消这次旅游,并且就会去启动取消去程的机票和预定的酒店。这个就说明当整个业务流程中的关键操作失败后,业务流程必须实行回滚操作。
补偿机制的设计有几个关键点需要考虑:
1、要使得一个业务流程能够执行完成,必须得保证流程涉及的所有的服务都必须是幂等性的,并且在整个流程的执行过程中需要有重试机制。
2、整个补偿机制的工作流是状态驱动的,所以需要时刻关注业务流程执行过程中的状态,当某个状态出现时需要有效地驱动工作流引擎中的下一个动作,继续执行或者进行回滚或者补偿动作。
3、当业务流程执行失败后,需要启动补偿的流程,这个补偿流程不一定完成是业务流程的反向操作,可以根据实际的情况来制定补偿的操作,目标就是补偿流程的启动要么就是保证业务流程执行成功,要么就是保证回滚到业务流程执行前的状态。
4、有些业务补偿操作不一定需要即时执行,在保证关键的业务操作执行成功的情况下,对于一些非关键的业务操作,可以推迟或者降低优先级执行。