粉丝3418获赞1.4万


说人话中,实战讲干货。你好,欢迎来到 it 老齐的架构三百讲,我是你们的 it 私人顾问老齐。到今年呢,我从业已经十八年了,一直做扎瓦与架构的研发工作。今年呢是我创业的第一年,目前呢,已经录制了十多门与编程架构相关的课程, 同时我还会提供点对点的简历优化、模拟面试、 offer 选择、解决方案、架构指导等服务。总之呢,只要是我有经验的,能给兄弟们帮上忙的信息呢,我一定坦诚相待。有需要的小伙伴呢,可以看一下评论区或者我的个人描述,希望能用我的经验帮你少走弯路,找到更好的工作。 今天咱们来聊一聊在分布式事物的这种场景下呢,里面包含的 a t t c c saga 还有 x c 这四种方案到底都是什么意思?我们平时在工作中 又该怎么去选呢?好的内容创作不易,希望兄弟们能给点一个免费的赞,谢谢大家了 啊,那咱们回到笔记来进行讲解。首先呢,我们重新回顾一下,为什么要有分布式事物呢?其实原因很简单啊, 我们在进行分布式系统开发的时候,往往系统和系统之间呢,他们底层呢就要产生一些联系,比如说我们在创建订单的时候,就要去扣减库存, 那此时订单创建是在我们订单服务的订单库中,而扣减库存呢,是要在仓储库中来进行扣减, 那因为我们底层是要在两个不同的数据库中来进行数据操作,那是如何保证数据要么全部提交,要么数据全部回滚呢?这里就有很大的学问了,这一讲 好呢,我就以咱们在开源领域非常著名的阿里巴巴开源的 cta 为例呢来讲解,到底它里边所包含的像 attcc, saga 还有 xa 模式到底是怎么回事儿? 那这里呢,我先给大家简单介绍一下。在 set 中呢,它有一个组件叫做 t c, 也就是事务协调者,它的主要作用呢,就是来向各个子服务呢,去下达全局事务提交或者全局事务回滚的这个命令, 那么它就相当于一个司令官来统筹我们整体的事务状况。那下面呢,我们就从最简单也是最容易理解的 a t 模式入手,了解一下它的使用场景和使用特点。作为 a t 模式是阿里塞塔独有的模式,它通过反向 生成 c 口语句的方式来帮助我们实现这个全局的数据的最终已知性。什么意思呢?来咱们看上面的图, 订单服务来新增订单的时候,是一条 insert 语句,那仓储服务对库存进行减少的时候,是一个 update 语句。按照正常的操作来说,那刚才在我说的两个服务中,是不是底层都要执行一个 insert, 一个 update 来完成数据操作啊? 那在这个过程中,其实作为 sayta 的 a t 模式呢,它呢是要求我们在每一个这个数据库中额外新增一个表,这个表名为叫 and do log, 这是 see 它的强制要求。那么这个 indoor log 表中呢,它要保存的是自动生成的回 滚 circle, 啥意思呢?就是我们利用 set 向数据库中执行 insert in two 语句的时候,在订单库中,它同时在 indle log 表中去执行一个 delete from 订单 vr id 等于一零零一,你可以发现他这里一个新增,那他就对应了一个删除,那 id 号呢,也是相匹配的。而这个自动删除的命令呢,是由 cat 底层的组件自动进行思考解析并反向生成的。 那与之类似,仓储服务对于仓储的这个存量数据呢?他呢进行了数据的减少,原先假设是二百一十,现在出库十个,现在呢变成了二百,那回滚日式中底层就记录了仓储表里边他的原始的值是二百一十,那这个安 logo 什么时候去使用它呢?假设我们前面的这个商城订单创建成功,库存也减少的话,代表整个事物就完成了,所以由 set 的 tc 这个事务协调者发起了全局事务提交以后,那么作为 这里的每一个回滚的 coco 就自动的被删除了。注意,回滚 coco 当遇到全局提交,就会被自动的删除,也就是说不用回滚。但是 如果此时 tc 呢,他发现我们刚才执行过程中,哎,比如说仓库扣减出错了,那我们要进行全局的回滚,那他此时由 tc 呢,会向每一个子服务下达回滚的命令,当收到回滚命令以后,由 cta 自动的去提 提取这个回滚表里边的对应的 co, 完成这个 delete 删除的操作,也就是说把刚才新增的订单记录呢,利用这个 delete 语句反向的来把它清除掉,这就是 at 模式,它的一个实现原理,整体的处理呢? cole 的生成, 回滚的这个数据删除或者还原,它都是由 set 自动完成的。那么作为 a t 模式呢?它的 使用特点呢,也非常的明确,首先呢性能还是不错的,因为它是基于 a p 的设计,保证了用户的可用性。 但是大家发现没有,刚才我在描述的过程中,其实是存在中间数据不一致的情况的。也就是说,在我们订单创建,但是库存还没有完成减少的时候,是不是就是一个不一致的状态? 存在中间状态,如果是在数据比较敏感的场景下,这种中间状态可能会带来一些额外的风险。 那么从使用角度来说,它呢使用非常简单,因为 set 呢,只是靠反向 c 口呢来自动的实现的回滚,我们大多数情况下不用关注底层的执行过程, 那使用要求呢,它这里主要有两点,第一个就是我们的所有的服务和数据库呢,都是要 我们自己开发拥有管辖权的,一般来说这个所有服务都归属到某一家公司,他们自己有数据库的管理权,因为我们要向每一个数据库中去额外增加安度 log 表, 那你总不能说要求其他公司配合你也要在他们自己数据库中加 undo log 吧,那有的时候这种情况很不现实。 第二个呢,就是对数据库的支持上,目前呢支持最好的肯定是 mac circle 或者 maria d b 啊,官方也说对 p circle 也支持,但是我没有测试过,不敢说 啊。那应用场景呢,是针对于高并发的互联网应用,允许出现短时的数据不一致的情况,一般来说,互联网的这种高并发应用,他呢为了保证数据的最终已知性, 会增加一些,比如说对账程序啊,或者补路程序呢,来保证我们数据是最终一致的,这是 at 模式的特点。那么我们再来说说 tcc 模式, t c c 模式呢,是一种反人类的模式,这里的 t c c 是三个英文单词的首字母,尝试确认和取消,那它对应了也就是三个步骤,分别是 try 呢, try 的阶段呢, 是对应的对于资源的锁定, t c c 模式下所有的数据提交和回滚都是要我们自己来实现的,所以呢,作为 t c c 是需要对原始的数据表进行修改, 在原始数据表中,假设只有订单编号,订单金额三个字段,但是呢,在 t c c 这里呢,我们还要额外增加订单状态和预增金额。 同时呢,在这个商品表里边,除了原有的库存以外,还有一个叫冻结库存。那么在我们 tcc 里边,首先第一个踹阶段呢,就是对我们的这个订单呢来进行一个冻结,具体冻结的措施是 新增订单的时候,那我们把这个订单的金额呢,首先写入到预增金额,注意这个字段叫预增金额还没有真正的产生,那 同时呢,当前的订单状态为初始状态,那下面呢,这个冻结库存,那我也是放到了冻结库存这一列,不是在当前库存中来进行减少,这是我们在踹准备阶段要做的事情,他把这些资源呢都先进行了一个预制的处理, 如果所有的数据库都预制成功了,下面呢由 sata 的 t c 呢去下发全局提交,也就是 confirm, 那我们就要对数据呢完成这个业务,具体的完成就是在订单服务中来底层数据表把我们预增金额加到这个真正的订单金额中,状态变成完成。 同时呢库存服务呢,也是按照原先的计算规则,一百减去十,剩余九十完成这个处理。但是如果我们这 这里的这个订单他中间出现了问题要取消的话怎么办?那就是把我们的这个当前的订单的状态变为取消,哎,取消订单吗?同时刚才冻结的不是十个库存吗?现在我们把这个冻结的库存十个给取消掉,那原始的库存不发生变化, 这样相当于整体呢就进行了回滚。那以上呢,你发现没有, t c c 呢?是针对于在数据表上面来做操作, 需要将哪些资源来进行一个冻结,那么它的特点是啥呢?首先性能还是不错的,他不会对资源进行长时间的锁定, 也是基于 a p 模式。哎,你看每一次操作完了以后,它是不是直接提交了呀?那数据的响应速度是相对快的,但是会存在跟 a t 模式一样的不一致的情况,它使用起来真的挺 反人类的。作为 c 塔,刚才我们说到的 t c 呢,就是事物的协调者,他只负责全局的事物的提交和回滚的操作,但回滚和提交他具体怎么做完全 是要靠程序员自己手撸代码来实现的,因为作为 cta, 他是不知道哎在什么阶段,哎,这个状态怎么变更?他这个金额到底是减跟哪个字段来进行交互,是加还是减他是不清楚的,所有的都是靠我们程序员代码来实现的,所以 t c c 呢,现在在工作中其实用的是比较少的,太恶心了。那么 t c c 呢,它有一些使用的要求,首先呢,因为涉及到要需要新增列,所以呢,要求我们自己的服务和数据库都有管辖权。第二个呢,就是他从这个数据库选型上来说 说,并不是特别的严格。支持易购数据库,你可以在数据库使用 masco 数据库,你可以在库存库使用 l reco 或者 pco 或者其他的数据库。因为所有的操作细节都是靠我们程序员自己来实现的吗? 但是呢,这里我还是提点建议,我们选择的这些易购数据库要支持事务,这样呢才可以保证单库操作的时候多表 事物是一致的。这是 t c c 模式的一个应用特点,那么它的应用场景呢,和 a t 基本是一致的,也是高并发的互联网应用,允许短时一致,可以通过对账程序或补路呢来保证最终一致性。这是第二种模式。 那第三种模式呢,是 saga, saga 模式在我们平时开发的时候非常的罕见,但是呢,它也有着自己独立的应用场景。 saga 呢,在这 这个 set 中呢,它是提供尝试物解决方案的,同时呢,它是通过状态机的方式来进行数据的补偿操作。 什么意思呢?来我说一个场景你就明白了。现在呢,我们要进行一个业务处理,那在业务处理过程中涉及到了三方支付,那 比如和微信、支付宝进行对接,要知道支付宝和微信他们是一个额外的组织,是不会受你受到你的管辖,这个关于支付宝的数据库你也无权去访问,所以像前面的 a t 和 t c c a 模式呢?如果在这种长事物和多节点, 尤其设计到第三方的情况下,其实是很难落地实现的,那么萨嘎呢,他就是解决这种问题的。在萨嘎中通过状态机的形式呢,为每一个操 操作步骤呢去拟定了一个正向的处理,比如说第一步是创建订单,第二个是支付,第三个扣减库存。哎,咱们按照这个来理解,作为状态机,那他还有一个逆向的处理,就是比如说 t 一对 c 一的时候,他是代表了这不是创建订单吗? 那对应呢就是删除订单,而 t 二刚才说的是支付是吧?好,那么支付那它对应的反向操作呢,就是退款, 而这个支付和退款往往都涉及到第三方来进行处理,所以是要调用第三方接口来实现的。 a t 三呢,涉及到库存的减少,那么到 c 三呢,就是库存的增加,所以 c 它呢,它是这样的一个基于类似于像事件流或者工作流一样,我们有这么一个流程引擎,帮助我们一步一步的去规 规划每一步,同时呢再给出相应的反向操作。那么沙嘎模式使用起来是比较复杂的,而且性能呢是 确定的,因为往往呢撒卡模式是用在和第三方交互,比如说和支付宝支付啊,或者像其他的这个机构服务进行调用的时候,像这种三方他执行的时间长短,往往就决定了咱们整体的这个操作的时间长短。 那作为 saga 呢,它是基于 a p 模式来实现的,也是存在中间的数据不一致的情况,那使用难易度呢?是 比较复杂的,他提交回滚的这些流程都要我们去增加这个正向和反向的节点。那至于使用的场景呢,就像现在咱们界面上看到了一个像画流程图一样,正向 接点,反向接点怎么处理?那作为萨嘎,他的应用场景是往往出现我们需要和其他第三方交互的过程中,第三方不受咱们管理,但是我们又要去保证最终的一致性,例如现在这种情况,现在呢,我们调用了支付宝的支付接口,相当于付款成功了,是吧? 但是紧接着在后面的处理中,我们自己进行出库的时候,出库失败了,那这时一旦出库失败,整个业务流程要回滚,他呢就会去调用这个支付宝的退款接口,把刚才支付的钱呢给充掉。 这就是我们说到的 saga 的一个应用场景,往往和三方交互的时候,为了保证数据的最终一致性所做出来的。那么他在使用的时候,需要在当前的工程,我们引入状态机机制,也就 是类似于像工作流的这样的一个引擎,他本身是比较重量级的,而且对这个事情的掌握的人不多,那这种情况下他的上手难度还是比较高的。 同时呢,因为在这里我们不涉及到具体的某一个事务俱护的选型,所以他是无法保证这个隔离性的。那这是第三种模式, 最后一种模式呢,是 x a 模式, x a 是最简单粗暴的,在我们数据库中会存在一种叫 x a 的协议来保证,通过两个阶段呢,保证数据的最终一致性。 x a 呢?它呢?说一下场景,我一说你就明白了,也是最好理解的。 我们 t c 新版的这个 sata, 它是支持了 x a 模式,比如说上边儿和下边儿两个都是 mac 或数据库,它呢,都是支持 默认支持 x a 协议的,那就以我们刚才的这个案例为准。这个订单服务和仓储服务,当我们在 x a 第一个阶段,订单服务他完成了 insert 语句的执行,注意此时订单服务并不会提交这个 insert 语句所产生的新纪录, 不提交就意味着这条数据被阻塞死。而仓储服务也是一样,它 update 减库存的时候,也是 第一个阶段先把这个 update 执行了,在我们事务中把它数据先减了,但是它不会提交。对于当前这一条仓储数据来说,它也是会产生一个阻塞的。 假设作为订单服务和仓储服务,他们都这两条四扣都执行成功了,于是由 c 他 t c 呢,在下发一个全局 提交的操作,那每一个具体的咱们服务呢?来执行 comet。 于是在我们最终的数据库中,订单表有了数据,仓储表也进行了库存扣减,这就是我们的 x a 的方案。 如果在刚才过程中仓储执行失败了,那作为 t c 呢,它会下达全区回滚的命令,那在我们订单的这个表里边,直接会执行数据库的 robac 回滚命令,把刚才事务区里边的数据给清除掉,这就是 x a 协议。 xa 协议呢,是依赖于数据库的这种特性来完成的,所以呢,它是强一致性的,我们不会出现中间状态,但是并发量是很低的,因为刚才你发现没有新增的订单会被 hold 住,卡死在那,而我们的仓储 土的某一个商品的这条数据,因为也是进行了库存的扣减,他也是会卡死全局,尤其只有唯一的一个县城呢,可以对他来进行访问,其他的县城都属于阻塞的状态, 这也是我们说到的强已知性他的一个问题所在。那么使用的难易程度上,确实这种情况非常简单,因为 这是数据库自带的事情。我们部署好了 set 的 t c 以后,它呢,不用做额外的太多的调整呢,就可以让我们在不修改表的情况下完成这个数据的一致性,那它的使用要求就是所有 支持 x a 方案的关系数据户都可以使用。同时呢,应用场景呢,在金融行业,因为金融行业涉及到钱,往往不允许 出现中间状态,对吧?那所以针对金融行业,在并发量不大的这种业务上,采用 x a 保证数据的全局的强一致是很有必要的。好,那讲到这里呢,我为你介绍了在这个分布式事务,以 seta 为代表的 a t, t, c, c, saga 以及 x a 模式,它们分别的使用的原理和它们对应的应用场景,希望能对你有帮助。