分布式金融核心探秘——分布式事务

Posted 睿观

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式金融核心探秘——分布式事务相关的知识,希望对你有一定的参考价值。

在系列文章中,我们将向读者介绍了下一代银行核心系统的最新趋势,以及在核心建模及数据分布的实践经验。

今天的文章,将带领读者了解分布式系统的核心问题,即分布式事务的设计。

早在互联网技术蓬勃发展之前,分布式技术及其相关理论就已经被提出、论证并加以实践。作为一种致力于解决单体系统计算瓶颈的技术,分布式技术随着计算对象的切分方式、切分后分片之间的关联关系,呈现出不同的特点,以及不同的实现方式。

总体来说,对于分布式系统的理解可以分为两种不同的类型:

- 单体应用的分布式

单体应用的分布式表现为将原有的单体应用变为多个实例进行处理。我们知道一个应用系统一般由应用部分与数据库部分组成。单体应用的分布式化是从应用部分的分布式先进行的,从应用的角度看,只需要将应用切分为众多无状态的实例,再依靠负载均衡,将请求按照一定的策略分发到这些对等的实例上,就算完成了应用层面的分布式。实际上,当前大多数银行的应用系统,从单体的角度上来看,就是做到这个程度。而对应的另一部分——数据库部分的分布式,往往需要依靠数据库厂商的努力,例如IBM在开放平台的DB2实际上一直到9.5版本之前,都只能以Active-Standby方式部署,而Oracle的RAC技术在更多的情况下是一种高可用技术,而不是为了解决性能瓶颈而发展起来——在CAP理论的限制下,保证了C和A的单体的应用的数据库分布式无法很好地完成P,即分区化。所以对于单体应用的数据分布式,主要通过分库进行,而这也将引申出本文的核心关注点:由于单体应用在设计时内部数据的互相关联而导致的在分库后的分布式数据一致性问题。

- 切分应用的分布式

由于前述的情况下,数据库分布式的障碍的存在,使得银行在构建系统时,倾向于使用切分应用的方式进行分布式化。将应用系统按照系统职责进行切分,而应用数据跟着应用系统一齐进行切分,相对于单体应用的数据库分库这种横向切分的方式,这种定义下的分布式化实际上是针对数据的纵向切分——即便如此,基于应用切分的分布式也会面临着分布式数据一致性的问题。

基于以上两种不同的分布式类型,每一种在以往都有着不同的分布式数据一致性的解决办法:

  1. 基于二阶段XA

XA二阶段模型

XA是一种分布式事务二阶段提交协议,支持XA的系统通过实现该协议,单体应用中通过这些实现了XA协议的事务管理器,进行事务的注册与协同提交,达到事务在多个XA事务管理器之间的一致。这种数据一致性的实现方式有以下缺点:

  1. 数据分布的特性必须向应用暴露,应用需要知道正在操作的数据分别属于哪个分片以及相应的位置,然后调用相应的事务管理器

  2. 性能问题。在XA的二阶段提交中,事务的参与方,需要持续的锁住相应资源,等待所有的参与方都完成准备和提交操作,这样随着参与方的增加,以及加上分布式环境里较为复杂的网络的环境,使得这种提交方式对性能上有很大的影响,特别对于银行常见的热点账户(例如核心系统的内部户),针对其的二阶段提交将使得整体性能相对单体应用有不可接受的下降。

  3. 软件依赖性,并不是所有的软件都实现了XA协议的二阶段提交,例如广泛应用的mysql直到5.0版本才支持XA,而一些非数据库类型是事务参与方,例如队列,对于XA的支持就更少。

 2. 基于冲正

冲正模型

当应用基于职责进行切分为不同的系统而完成分布式,保持该情况下分布式数据的一致性往往依靠实时进行的冲正,或者非实时的对账以及差错调整进行。我们主要研究并分析面向联机的实时冲正的一致性模型。在该种模型下,当事务参与方出现交易失败时,分布式协调者(通常是发起方或者类似于总线类系统)需要将其他参与方已经完成的交易进行冲正,以确保分布式数据的一致性。这种模型的缺陷如下:

  1. 在交易的过程中,当一个事务参与方完成自身部分的交易后,实际上数据已经落地,这个时候如果发生其他交易,该数据将会与分布式事务发生前不一致,从而导致分布式事务的冲正失败

  2. 传统架构下,不同系统的通讯方式、服务的实现方式、冲正交易的实现都可能不同,将使得分布式事务协调者的实现极为复杂。

接下来,让我们将介绍一种分布式事务的实现:

基于应用二阶段模型

上图描述的分布式事务一致性其实现原理如下:

  1. 应用都统一实现三个接口:prepare、confirm、cancel三个服务接口,作为统一的分布式模型供分布式协调者统一调用

  2. 分布式事务的处理顺序为:

    a)         分布式事务发起者发起本地事务并向分布式协调者注册该事务,而后开始调用各参与方

    b)        分布式发起者顺次调用参与方的prepare接口:将事务操作对象需要变动的部分进行预留,这里需要应用层面设计,以“预留”代替锁定,完成prepare服务后,相应的资源被预留供进一步处理,prepare所在应用当前的本地事务在prepare完成后完成

    c)         分布式协调者根据各参与方的prepare接口返回,确定调用各参与方的confirm或cancel接口,调用confirm接口将落实预留资源的消费,而cancel将释放预留的资源

相对前述的各种实现的方式,它有以下特性:

  1. 较好的性能,不能像XA那样过长时间地持有资源。由于在应用层面使用预留模型,数据库处理与单体单实例数据库事务是相同的,因而所有更改会被马上落地,不存在数据库层面的锁定。

  2. 较简单的分布式模型,分布式协调者面对的是统一的技术构型,统一实现了prepare/confirm/cancel接口,分布式发起者和协调者基于这个模型构建,简化了构建的复杂度。

  3. 较少的软件依赖,这个模型实现为应用级别的功能实现而不依赖于特定的数据库或其他交易管理器。

  4. 对分布式数据的分库策略透明,由于使用应用级的事务接口,如上一篇文章的分库方式中介绍的,应用通过分库中间件进行分库策略化处理,每一个应用实例都是对等的,对于分布式事务发起者和协调者,只需要调用该应用的任意实例就能访问至数据分片

当然,该方案也同时对应用自身的设计提出了要求和挑战:

  1. 如果是一个现有的系统,当原有的服务需要都变为prepare/confirm/cancel三个接口,如果该系统本身就能将自身的服务实现逻辑放置在一个有序的组装模型上,就能够大大降低改造的复杂度,而这样的组装模型通常要求应用设计上有一个较为抽象的核心数据模型

  2. 相应的,开发人员如何很好地处理prepare和confirm之间的分别,也对开发人员自身对于系统和业务理解提出较高的要求,与第1条要求相似,基于一个较好的组装模型,prepare、confirm和cancel有各自固定的组装模型,才能够尽可能地将分布式的复杂性向开发人员屏蔽

  3. 而相对组装模型,数据模型则是更底层、更核心的部分,如何在原有的应用逻辑中实现“预留”,并且所有的交易场景下的预留,而这些是否能够在不进行数据模型的改动下实现,对于数据模型设计有较高的要求。一个充分抽象的数据模型,例如针对余额类型进行了充分的抽象,就能够简单地加入一种冻结类型的余额用于预留,避免需要横向扩展原有的账户表结构——而这正是大多数现有系统在改造时将遇到的难点。




以上是关于分布式金融核心探秘——分布式事务的主要内容,如果未能解决你的问题,请参考以下文章

探秘蚂蚁金服分布式事务 Seata 的ATSaga和TCC模式

分布式事务:蚂蚁金服核心金融场景下的演进

Fescar分布式事务实现原理解析探秘

数据库系列之金融分布式事务数据库白皮书解读

动态金融分布式事务数据库研讨会在京召开

分布式事务资料