分布式事务揭秘
分布式事务的由来
分布式架构下,将原来揉在一个单体系统的业务,按照一定的方法论进行梳理,拆分出独立的一个个子系统,例如用户微服务、订单微服务、库存微服务等,将单体系统的压力分散,以提高整个系统的吞吐量和并发量,增强整个系统的灵活性、伸缩性和稳定性。
但分布式架构在事务处理上也带来了挑战,在单体架构中,业务数据的完整性和一致性可以用本地事务来保证,但是在分布式架构下,数据资源的部署方式由单一集中转变为分散隔离,本地事务只能保证某一个数据资源的完整性和一致性,如何保证分布式架构下这些分散部署的数据资源在同一交易中的完整性和一致性,就是分布式事务要解决的问题。
常见的分布式事务解决方案
分布式事务,有多种多样的处理方式。有被动方式,通过一定方法避免分布式事务的发生,如共享数据库模式;也有主动方式,直面分布式事务的痛点,通过精细的管控,解决分布式事务的问题,如事件队列模式,服务编排模式和多阶段控制模式。
1、形式上的微服务:共享数据库模式
多个微服务共享同一个数据库,每个微服务可以读写其他微服务管理的数据,基本消除分布式事务,相当于单体事务,是一种避免分布式事务的逻辑。
这种模式业务实现复杂度低,虽然业务做了微服务拆分,但是系统压力全都集中在单一数据库中,系统性能容易造成瓶颈,分布式架构的高并发量、强伸缩性优势遭到破坏。相当于形式上是微服务,数据库层面还是单体系统。
2、协同下的微服务:事件队列模式
eBay 的架构师 Dan Pritchett,曾在一篇解释 BASE 原理的论文《Base:An Acid Alternative》中提到一个 eBay 分布式系统一致性问题的解决方案。它的核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。在这个模式下,每个微服务使用各自独立的数据库,业务数据写入自有数据库时,同时通过消息队列,发送消息到关联微服务,关联微服务消费消息后将数据写入关联数据库中,实现多个微服务间的数据通过消息队列协同变化。
但这种模式无法做到实时双写,有一定的延迟,也会有一定短时数据不一致。当关联数据库写入失败时,需要通过消息队列发送回滚消息,来实现不同微服务间数据的最终一致性。
3、编排下的微服务:服务编排模式
编排模式是通过正向交易与补偿交易联合工作,实现不同微服务事务的最终一致。
编排模式通过编排的方式,对交易链路中的每个交易设计正向交易和补偿交易,当正向交易都成功执行时,整个交易链路顺序推进;当某一个正向交易执行失败,则由编排引擎,自动发起重试,重试也失败后,发起回滚流程。这时编排引擎按照预先编排的内容,对交易链路中的每个交易按顺序一一调用补偿交易,进行回滚,直至所有交易都回滚到正常状态。
通过编排控制,结合重试和回滚,使分布式系统达到最终一致的状态,避免了对分布式事务集中控制的需求。但是编排的方式要求业务逻辑通过编排实现、业务的服务提供者需要支持回滚和幂等,对业务开发要求较高。
4、协调下的微服务:多阶段控制模式
多阶段控制,利用分阶段事务处理的思想,通过统一的事务协调者,统一协调各微服务进行事务提交的准备、事务提交的尝试、事务提交及回滚等操作,实现分布在各微服务中的独立事务,按照协调器要求的节奏统一推进或回退,来保证各微服务事务的一致。这个协调者一般是独立的协调服务。
多阶段控制一般有如下模型:
2PC 模型:2PC(Two-phase commit protocol),中文名叫二阶段提交。传统二阶段提交是一种尽量保证强一致性的设计,有多种具体的实现形式。2PC 模型引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,此模型中的二阶段指准备(投票)和提交两个阶段。
3PC 模型:3PC 的出现是为了解决 2PC 的一些问题,3PC 包含了三个阶段,分别是准备阶段,预提交阶段和提交阶段,相比于 2PC,它在参与者中引入了超时机制,解决 2PC 在二阶段提交失败时,不断重试而导致一阶段一直阻塞的问题,并新增了一个阶段使得参与者可以利用这一阶段统一各自的状态,使得故障恢复之后协调者的决策复杂度降低。但 3PC 模型相比 2PC 模型,整体流程更长,性能有所下降。
TCC 模型:如果说 2PC 和 3PC 模型是数据库层面的分布式事务解决方案,那么 TCC 模型就是业务层面的分布式事务解决方案。TCC 是 Try、Confirm 和 Cancel 的缩写。在业务处理之前先对本地事务资源进行检查(try),如果各个参与方的检查都成功,则进行真正的事务处理(confirm),否则就进行回滚(cancel)。TCC 模型在保证强一致性的同时,最大限度的提高系统的可伸缩性和可用性。
中原银行分布式事务实践
中原银行基于阿里巴巴的开源框架 Seata 打造了行内的金融级分布式事务框架,并提供了可视化的分布式事务管理端,与中原银行流程编排一起构成了行内高性能分布式事务底座,命名为 DTM。
中原银行的分布式事务框架延用了 Seata 的四种分布式事务模式,AT,XA,TCC 以及 Saga。这四种模式都使用了独立于业务服务之外的协调服务。
其中 AT 模式和 XA 模式是业务无侵入的“全自动”分布式事务,适合使用 JDBC 访问关系型数据库、短链路的分布式事务,不同的是,AT 模式是最终一致的,XA 模式是强一致的;TCC 模式是自定义两阶段的分布式事务,不依赖关系型数据库,有业务侵入,适合复杂业务的分布式事务场景;Saga 模式具有高吞吐的特性,适合长事务。
1、AT 模式
AT 模式是 2PC 模型的变形,最终一致性的分布式事务解决方案。AT 模式必须基于支持本地 ACID 事务的关系型数据库,同时还必须要是通过 JDBC 访问数据库。AT 模式只需要通过一个 @GlobalTransaction 注解就可以实现分布式事务,没有任何的业务侵入。其基本原理是解析 SQL 语句,由框架来生成回滚日志,由框架来进行事务异常后的回滚,隔离性由框架的全局锁来保证。
AT 模式基于其业务无侵入、全自动、低学习成本的特性,是最适合入手的模式,但是这种模式也具有一定的局限性,它只能保证全局事务的最终的一致性,会在整个事务完成之前出现短暂的不一致。基于这些特性,AT 模式适用于对数据一致性要求不是特别严格,但是又不希望对业务进行侵入改造,且调用链相对较短的场景,如数据同步,商品购买,限额更新等典型的电商链路场景。中原银行的对公渠道中台动账类业务涉及交易服务、审批服务与限额服务,整个流程较短,就可以用 AT 模式无侵入的实现分布式事务。但是因为其全局锁的机制,AT 模式并不适合对某一条数据频繁更新的场景,如商品秒杀、抢票等。
2、XA 模式
XA 协议的实现,XA 协议由 Tuxedo 首先提出的,并交给 X/Open 组织,作为资源管理器(数据库)与事务管理器的接口标准。Oracle、Mysql、DB2 和 Sybase 等各大数据库厂家都提供对 XA 的支持。XA 协议一般分为 XA_START,XA_END,XA_PREPARE,XA_COMMIT/ROLLBACK 这些阶段,其中在 XA_START 和 XA_END 之间执行 SQL 语句,这样 XA 协议可以认为是 3PC 模型,为了提高性能,Seata 将前两个阶段合并为一个阶段,也就是把 XA_START,XA_END 以及 XA_PREPARE 作为一个阶段,XA_COMMIT/ROLLBACK 作为一个阶段,由 3PC 变成了 2PC。XA 模式由数据库加锁,保证其强其一致性和隔离性,因此在性能上稍差一些。Seata 的 XA 模式做了从 3PC 到 2PC 的优化,而在同一个 Oracle 数据库实例中,XA_PREPARE 命令之后就不允许再执行 XA_STRAT,因此 Seata 的 XA 模式对 Oracle 数据库支持不是太友好。
XA 模式也是业务无侵入、全自动的分布式事务模式,与 AT 模式不同的是,其底层是关系型数据库来实现加锁的,整个业务过程中是数据资源是强一致的,适用于 AT 模式的业务场景同样可以替换为 XA 模式。但是 XA 模式是有性能损耗的,这个性能损耗主要来自两个方面:一方面,事务协调过程,增加单个事务的 RT;另一方面,并发事务数据的锁冲突,降低吞吐。但是,在极短事务下,其性能与 AT 模式相差不大,这一点在我们的性能测试中已经得到验证。基于以上特性,XA 模式适合需要让在同一个事务上下文中被协调的多种资源保持强一致性,但不希望对业务进行改造,且调用链路很短的场景,如数据要求严格同步的场景,如简单的数据双写。需要注意的是,如果在 Oracle 数据库中使用这个模式,必须保证每一个分支事务要操作的数据库必须是不同的数据库实例。
3、TCC 模式
TCC 模式就是 TCC 模型的实现,可以把 TCC 简单理解为“自定义的 AT 模式”,一阶段和二阶段要做什么,完全由开发人员自己来实现,框架提供符合 TCC 模型的 API,只需要在开发过程中使用相关 api 即可以 TCC 模型来实现分布式事务,需要注意的是,由于 TCC“自由”的特性,在开发过程中需要有更多的考虑,比如,在业务实现上要考虑到幂等,一阶段没有执行的情况下要考虑到空回滚问题,这就需要相关人员在业务设计上更加契合 Try-Confirm-Cancel 这一设计。
TCC 模式“自由”的特性决定了它是业务侵入性的模式,但是在一定程度上,如果有合理的设计,这种模式既能保证一致性,也能有不错的性能,在金融系统中,TCC 模式可以做核心系统中的定制化的账务处理。
如上图所示,一阶段的任务是先检查余额是否足够,再冻结要扣款的 30 元,此阶段不会发生真正的扣款,二阶段根据整个业务流程来决定是执行真正的扣款,还是释放被冻结的 30 元。除了这一典型的扣款业务,TCC 模式同样适用于业务系统链路中某一阶段操作的是非关系型数据库资源,但是这一数据资源需要保证与其他数据资源一致性,这样 AT 模式和 XA 模式就无能为力了,TCC 模式恰好可以解决这一问题。
4、Saga 模式及流程编排
1987 年普林斯顿大学的 Hector Garcia-Molina 和 Kenneth Salem 发表了一篇 Paper Sagas,讲述的是如何处理 long lived transaction(长活事务)。Saga 是一个长活事务可被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务。Saga 的基本原理是业务流程中每个参与者都提交本地事务,当出现某一个参与者失败时补偿前面已经成功的参与者。
中原银行现有对 Saga 的实现有两种方式,一种是 Seata 的 Saga 模式,一种是已经在中原银行已推广使用的流程编排。前者是偏向于编码的方式实现 Saga 模式的分布式事务,其基本原理是状态机引擎驱动事务的执行,既可以对失败的事务向前补偿,也可以继续向后执行,比较灵活,后者是以“拖拉拽”的方式绘制事务流程,其基本原理是通过扫描事务状态表来实现。前者有事务协调器参与,可以统一监管分布式事务,后者只能通过日志或者流水表排查,开发者可根据使用习惯自由选择如何进行开发。
Saga 的思想本就是致力于解决长事务,其无锁的特性决定了这一模式的高性能、高吞吐。因此,Saga 模式及流程编排适用于业务流程长、业务流程多,分布式事务的参与者相互松耦合、有搞吞吐需求的的场景,在中原银行内部,这种模式在信贷业务中得到广泛应用,信贷业务具有流程提交、额度占用、发放贷款等一长串的业务处理,使用 Saga 模式或者流程编排可以保证整个业务具有较高的吞吐量。对公渠道中台的后管业务涉及的微服务较多,也使用了这种模式。
5、DTM 管理台
中原银行在 Seata 的基础上,建设了分布式事务管理台(DTM 管理台),实现了分布式事务的集中管理,提供全局事务查询、分支事务查询、AT 模式下全局锁控制能力。管理台按照接入的系统进行隔离,中原银行各个系统在对接分布式事务平台之后,可以管控本系统的分布式事务。
结语
在分布式架构中,处理分布式事务并没有完全正确或错误的模式,每种分布式事务解决方案都有其优缺点,每种模式都能解决一些问题,但是反过来又会带来其他的问题,没有一个银弹能够适配所有业务场景。我们对中原银行现有的分布式事务模式做了总结对比,提供了选择的大致方向。
业务需要什么样的解决方案,还需要结合自身需求、业务特点和技术架构进行综合分析,才能找到最适合的方案。中原银行分布式事务平台,支持多样化的分布式事务模式,满足各个业务系统的不同诉求,以企业级的建设思路,支撑中原银行分布式架构转型和业务快速发展。
参考文献
[1]《基于 Seata Saga 设计更有弹性的金融应用》 屹远(陈龙);
[2]《分布式事务 Seata 及其三种模式详解》 屹远(陈龙)
本文转载自原银科技微信公众号
原文链接:分布式事务揭秘
版权声明: 本文为 InfoQ 作者【中原银行】的原创文章。
原文链接:【http://xie.infoq.cn/article/68c7777e61dbe359d36be3158】。文章转载请联系作者。
评论