用友微服务事务一致性实践
导读:
本文就微服务事务一致性问题产生根源、业界常用方案优缺点进行了分析对比,在此基础上提出了用友微服务事务一致性解决方案,详细介绍了用友CC事务模型及原理,以及此方案解决的场景。
一致性问题的产生
在传统巨石应用架构模式下,架构特点主要是mvc模式,由controller层负责对外提供服务接口,所有功能集中在一个服务实例中,通过增减服务实例来扩展集群的处理能力,但数据持久化集中在一个数据库存储,数据一致性主要依靠传统数据库本地事务机制保证,这种架构模式特点是简单、快捷,方便业务规模不大,业务功能单一的场景,随着业务增长,无论是业务规模还是业务范围都在快速变化,这种巨石架构模式就显得力不从心,不易于开发协调,因此,微服务架构模式应运而生,所谓微服务通俗来说就是对服务进行垂直拆分,将一个整体服务拆分成功能相对独立的单元服务,各单元服务之间通过rpc进行同步或异步调用。微服务架构模式下各个服务单元各自有独立的数据持久层,一个业务请求需要多个微服务单元共同协作,要求各服务单元要么同时成功或同时失败,但微服务实例分别部署在不同的进程或主机节点上,每个服务实例的状态、网络等情况是不可预知的,因此,如何保证一个业务请求中各单元服务数据保持一致性成为微服务架构中一个关键的问题。
常见解决方案
两阶段提交
两阶段提交属于刚性事务,两阶段分为准备阶段和提交阶段,在准备阶段,由事务协调器向各个参与者发送Prepare消息,参与者收到消息后,要么返回失败,要么执行本地事务,并写本地redo和undo日志,但是并不commit事务,此时,本地事务资源是被锁定状态,其它服务或应用是不能使用此资源的。在提交阶段,事务协调者在接收到所有参与者事务消息通知之后,根据所有参与者提交阶段返回的状态确定在提交阶段是回滚还是提交事务,只要有一个参与者超时或者失败,协调者就向所有参与者发送回滚请求,否则就向参与者发送提交请求。
二阶段提交的优点
1)实现了事务的隔离,确保了强一致性,即本地事务未提交的数据对其它事务不可见,事务要么都提交成功要么都失败
2)业务编程简单,由于事务管理是由事务协调者及本地事务资源管理器实现,开发者必须要介入太多事务相关的工作
二阶段提交缺点
1)同步阻塞调用,在事务执行过程中,所有参与者同步锁定资源以实现隔离,被锁定的资源不能被其他事务访问
2)需要本地事务支持,即本地数据库需要支持xa协议
3)需要事务协调者,协调者存在单点问题
4)事务会出现无法确认的状态。当协调者发出commit请求后,然后协调者宕机,而参与者可能只有一个已提交,其它参与者尚未提交,此时如果唯一的参与者也宕机,整个事务状态将无法确认
5)主要解决的单JVM跨库的事务一致性
TCC事务
TCC事务即Try-Confirm-cancel三个阶段,是柔性事务的一种,实现的是最终一致性,适合于同步调用过程。TCC是应用层的两阶段提交,不需要事务本地数据库对XA协议的支持。TCC事务模型有三个部分组成
·主业务服务
主业务服务为整个业务活动的发起方,通常是服务聚合应用,比如商城系统的下单系统,下单时需要调用库存系统减库存,支付系统付款及积分系统给用户积分以及购物车系统清理购物车内容。
·从业务服务
从业务服务负责提供TCC业务操作,是整个业务活动的操作方。从业务服务必须实现Try、Confirm和Cancel三个接口,供主业务服务调用。由于Confirm和Cancel操作可能被重复调用,故要求Confirm和Cancel两个接口必须是幂等的。
·业务活动管理器
业务活动管理器管理控制整个业务活动,包括记录维护TCC全局事务的事务状态和每个从业务服务的子事务状态,并在业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消时调用所有TCC型操作的cancel操作。
1)Try:尝试执行业务
完成所有业务检查(一致性)
预留必须业务资源(准隔离性)
2)Confirm:确认执行业务
真正执行业务
不做任何业务检查
只使用Try阶段预留的业务资源
只要Try阶段执行成功,需要确保Confirm一定成功,可以不断重试
3)Cancel:取消执行业务
释放Try阶段预留的业务资源
只要try阶段失败,必须确保Cancel最终一定成功
TCC模式优点
1)解决了跨应用的事务问题
2)把数据库层面的两阶段提交提到应用层来实现,不需要数据库层面来支持XA协议,规避了数据库的XA支持的缺陷
TCC模式缺点
1)需要从业务的角度来设计业务接口,确保业务可分解成Try、Confirm、Cancel三个阶段,增加了业务编程的复杂性
2)由于每个应用的网络不一定可靠,可能会多次调用业务接口,需要业务层面考虑幂等性操作
3)由于三个阶段都是同步调用过程,因此随着参与者增多,对主业务响应速度有影响
基于消息队列的最终一致性
基于消息队列的最终一致性考虑的场景是业务之间通过异步调用来实现,即作为服务调用方发起方异步调用之后立即返回,不必等待被调用服务实际返回结果,这样就可以基于消息队列来实现业务之间的解耦,由各业务来确保最终一致性。
基于消息队列的最终一致性方案的优点
1)各业务之间完全解耦,单个业务性能不会影响整体服务
2)有助于提升服务的整体性能和吞吐量
3)实现起来简单,只需要参与事务的各方在收到消息后确保本地事务一致性、幂等性
基于消息队列的最终一致性方案的缺点
1)需要业务调用方来确保本地事务和发送消息的原子性,虽然像ActiveMq支持事务消息,但是事务消息对性能影响较大,可以在本地建立消息表的方式来确保本地事务与发送消息同时成功或失败
2)当出现不一致时,需要人工介入处理各个业务的执行状态
用友微服务事务一致性解决方案
用友微服务治理中的事务一致性解决方案综合了TCC与基于消息队列的最终一致性,CC事务模型,即Confirm 和Cancel模型。该模型将分布式事务边界划以异步调用为边界,只要在调用链中加入事务的同步调用,都属于一个全局事务,在这个全局事务中,保证事务的最终一致性,如图:
在此图中一个完整的调用链从A服务开始,在左边方框内是rpc同步调用,而右边也是一个rpc同步调用,两个方框之间的服务C是通过异步调用框架EOS基于可靠消息队列对服务E发起调用,CC事务模型将此次调用当做两个事务处理。
CC事务模型事务状态变化时序图,rpc调用链关系为A->B,B->C,B->D,C->E,时序图如下:
CC事务模型过程,A同步调用B服务,事务框架在A服务内部数据库记录对B的调用上下文及事务记录,事务状态为Confirming状态,同时,rpc框架将事务上下文传递给B,B服务接收到rpc调用请求,B服务记录事务,同时事务为Confirming状态,同理,B调用C,C调用E,B调用D.此时,如果B调用D异常,则B本地事务回滚,同时B服务捕捉到异常后根据B服务记录的调用关系上下文,通过EOS框架向C和D发起异步补偿方法调用,所有方法补偿方法调用成功,则B事务状态为Cancelled,C服务补偿调用成功后继续向E服务发起异步补偿调用。同时,B向A抛出异常,A捕捉异常后执行补偿异步调用,同时本地事务回滚,最终AB事务状态为Cancelled或者Confirming状态,C、D、E已提交事务执行补偿方法后状态为Cancelled.最终,所有的事务状态都会confirmed时,则事务成功,或者所有状态都为Cancelled时,回退成功,如果有节点处于Confirming状态,说明整个事务发生了不一致状态,需要人工介入处理。
CC事务模型优点
1)没有事务管理器的概念,每个事务节点都是对等的
2)模型简单,代码侵入少,开发者只需要在业务接口上方法上使用@CCTransaction(cancel='异常时补偿事务方法')标识此方法纳入事务管理,同时,补偿方法上加入@CCTransCancel
3)异步消息补偿机制。事务补偿机制通过EOS可靠消息投递,减少事务补偿回调对业务系统性能的影响
CC事务模型缺点
1)该事务模型与自研rpc框架iris绑定,不支持其它rpc框架
2)没有Try阶段锁定资源,一进入事务本地事务就已实际提交,不具备事务隔离能力,业务需要考虑如何实现Cancel才能符合业务实际回滚需求。