转载本文需注明出处:微信公众号EAWorld,违者必究。
分布式事务解决的问题很明确,就是在服务分布在不同进程、数据分布在不同数据库时,如何解决数据一致性问题。对于这个问题,业界的共识是不要启用数据库 XA 模式,因为分布式情况下,如果启用了 XA 事务,必然会有数据库锁存在,实际上造成了两个服务之间的耦合,与分布式服务的初衷背离,还不如部署在一起。在不使用 XA 的情况下,经常使用业务补偿和TCC(Try/Confirm/Cancel)模式的服务来解决:为什么有这样两种模式呢,他们有什么区别,各自适合什么样的场景,这两种模式是否带来了代码开发的复杂度?经常有人问我这样的问题,这里简单说明一下:
用补偿交易保证数据一致性
解决数据一致性问题,可以通过业务补偿的方式完成。实际上业务补偿是一种业务提出的要求,在银行我们可以把交易(服务)分为账务类和查询类交易(在这里服务和交易是等同的,我就不再专门区分了),对于账务类交易,可以提供补偿交易,一旦业务失败可以调用补偿交易,通过冲正等方式进行,如何补偿在业务上是有明确定义的,不能随意而为。(不要担心这样做开发起来复杂了,这是必须做的需求)。
当年很多业务在失败的时候,是由人工发起补偿交易的(我在阿里展览馆就要这样的展品,在一个小本本上手工记录的交易金额、流水号等,早期的支付宝就是这样冲正的)。这样做法效率低,我们就希望能够通过技术手段,在业务失败的时候自动发起补偿交易,减少人工参与。为此,我们可以开发一个自动补偿的框架,记录每个处理过的业务交易流水,在处理某个交易失败的时候,依次调用补偿交易,流程如下:
TCC服务(交易)的使用场景
银行的账务类交易除了补偿类交易之外,还有一种 TCC 类型的服务,这类交易的 T 是 Try 的一起,也就是开始时预留资源,在 Confirm 的时候改变最终资源,或者在 Cancel 的时候释放预留资源。例如,在银行账目中,都有余额和可用余额两个字段,在 T 的时候,首先改变可用余额,业务上用可用余额来进行判断,而不是用实际余额判断,在 Confirm 的时候,修改实际余额,在 Cancel 的时候,修改可用余额。
这样做的好处是,在业务失败的情况下,实际余额不会出现变化。我经常遇到的问题是:
-
有了补偿服务为什么还要 TCC,有什么好处,为什么不能直接修改账户余额;
-
TCC 服务要用什么样的框架实现。
TCC 这种做法有什么好处
以前面账户余额和可用余额的例子看,账户余额的调整会涉及到很多方面,不仅仅是一个字段数值的更新,根据会计原则,账户余额的变化需要生成会计分录、登记账务流水、计算利率变化、计算税率变化等等,除此之外,账户余额的变化还会引起关联账户的变化,牵一发动全身。在业务失败的时候,如果调用补偿交易,就需要对上述操作做处理,业务处理太复杂,得不偿失。因此,一般会设计一个可用余额,首先改变可用余额,业务成功时再调整账户实际余额。根据这个示例,我们也可以清楚,在什么场景下需要 TCC 服务了。其实,在金融交易中,就有专门的预付费交易,就可以用来支持 TCC 模式。
(点击图片可放大)
TCC 服务要用什么样的框架实现?
从上述示例可以看出,TCC和补偿式交易一样,都是为了满足业务的要求,而这些交易恰好可以用来为数据一致性服务,TCC服务的 T、C、C实现,完全是根据业务需要实现,不可能有一个统一的实现框架,例如账户余额的做法和库存余额的做法,可能是差距很大的,没有必要抽象出来。互联网上虽然有实现 TCC 服务的方式,但是也都是针对特定业务的,不具备通用型。
但是,为什么往往有人提出,框架要支持 TCC 呢,究其原因是把 TCC 服务和数据一致性框架混为一谈了,前者是一个服务实现,后者是利用服务的特点保证数据完整性,减少人工操作。
数据一致性框架,除了利用 TCC/补偿服务的框架之外,还有利用幂等服务特性实现的重试性框架,也就是利用交易的幂等特性,反复进行重试,如果多次重试还是不成功,只有采用人工手段了。
总结一下:
补偿类服务和 TCC 服务是处理重要信息变更的两种模式,可以通过这两种模式,来支持数据一致性。这两种方式都是特定业务的需要,而不是 XA事务、重试这样,用一种技术手段实现数据一致性。对于简单的业务来说,这两种方式是没有必要的,但是对于重要信息的变更,尤其是分布式系统从渠道、中台、核心多环节完成信息变更时,这是必须的。
关于作者:焦烈焱,普元信息CTO,致力于技术创新和金融创新解决方案研究。专注于企业技术架构领域,对分布式环境的企业计算、 企业信息架构的规划与实践有着丰厚经验,带领普元技术团队相继在云计算、大数据及移动开发领域取得多项突破,并主持中国工商银行、中国建设银行等多家大型企业技术平台的规划与研发。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。长按二维码关注!