
总结分布式服务事务的基本概念首先需要对分布式服务有一个概念其中核心为同一网络下不同组件通过网络进行通信和协调对外一个如同一个整体。然后事务的需求就是不同的服务使用的是不同的数据库这就导致不同服务数据库的一致性不能保证。举个例子你就会明白了a服务会调用b和c服务bc都会修改数据库当a调用服务时bc都会修改各自的数据库。但是如果出现突发情况导致b失败与此同时c依然在执行并且成功。就会出现如下情况a服务调用失败可这次失败却导致了c服务数据库的改变且a无法操作数据库让其回归正常水平这在开发过程中是完全无法接受的。所有我们就需要进行处理这个问题那么处理的方案就叫——分布式事务接下来我们就来讲讲分布式服务的基本构成1.事务协调者transaction coordinator 简写TC外部引用组件作用协调所有参与者管理全局事务常用组件Seata TC最常用国内微服务首选Atomikos TransactionNarayanaBitronix Transaction Manager2.事务发起者transaction manager 简写TM全局事务发起者作用:发起事务3.事务参与者resource mananger 简写RM事务参与者作用:参与事务主体有了接下来就是关于事务是如何运转的了首先TM需要向TC进行交互,TC会得到本次事务的一个ID接下来RM会从TM拿到ID这样事务的绑定就完成了。RM会正常执行指令 在这个过程中会出现两种情况如果所有RM都完成所有事务就会提交如果有任一RM失败所有事务都会进行回滚这就是事务基本流程根据不同市场需求会进行很多变种当万变不离其宗整体思路是不会变的。然后还有一个小概念的分类全局事务分布式事务包含所有的分支事务分支事务又称为本地事务某个服务的本地数据库事务这是个很容易记住的一个小概念理解型记忆没什么难的分布式事务解决方案市面上的解决方案有很多但是我到今天为止知道的只有4种后续可能会增加也可能不会谁知道呢。1.XA协议数据库协议1991 年提出的一个协议方案由于当年的网络并不发达导致该协议并不能在高并发的情况下运行多用于远古项目和传统金融核心、银行、保险、财务系统其步骤为1.TM向TC发起事务开始声明并给予执行ID2.RM得到ID进行执行执行完成后不提交保持数据库连接3.TC会等待所有RM执行完毕后进行汇总根据结果进行提交/回滚。总结由于其时代背景其解决了分布式服务的功能需求但在当今网络已经不太适应只有少量项目在苦苦支撑。时代的洪流滚滚而去又谁记得他曾经的辉煌呢?反正我记不到。Saga 模式Saga的核心思想把一个全局事务拆成一串本地子事务每一步子事务都有对应的补偿动作回滚逻辑其核心步骤有abc3个事务当有任一事务失败时候a执行a1回滚ab执行b1回滚bc执行c1回滚cTCCTry-Confirm-CancelXA 在互联网大规模分布式系统里太重数据库层锁阻塞、性能差应当把分布式事务提升到业务层由业务做资源预留而不是数据库锁。所有TCC模式应运而生他解决了数据库连接挂起的情况在互联网支付、钱包、账户系统支付宝、微信支付、各类支付平台等新支付模式下如同一枚新星冉冉升起。其核心分为4步两阶段走1.TC调用所有接口并汇总业务结果2.Try一阶段业务校验 预留 / 冻结资源本地事务提交直接释放数据库资源3.Confirm二阶段 - 提交全部 Try 成功协调器调用 Confirm确认执行业务使用预留资源幂等4.Cancel二阶段 - 回滚任意 Try 失败协调器调用 Cancel释放冻结资源幂等总结解决前面数据库连接占用的痛点处理灵活但其confirm和cancel需要进行构建和思考对于业务能力要求高Seata AT模式Apache Seata(incubating) 是一款开源的分布式事务解决方案致力于在微服务架构下提供高性能和简单易用的分布式事务实现方式1.在各个事务的数据库中建表 undo_log表2.直接执行业务seata代理数据源DataSource)拦截sql执行提取sql执行前后的数据镜像将前后数据镜像转化成一条sql加入到当前本地事务执行提交插入到undo_log表中3.如果所有参与者都处理成功TC 协调所有参与者直接删除undo_log记录如果存在参与者处理失败TC协调所有的参与者回滚参与者从undo_log表中提取前后镜像计算得到逆向补偿sql执行sql实现补偿总结简单通用性能高解决数据库挂起痛点但缺点很明显对于复杂业务无法处理Seata的AT模式全局事务执行过程重点扩展一下Seata AT模式其运行流程如下1.GlobalTransactional开启全局事务TM 向 TC 申请全局事务TC 生成全局唯一 XIDXID 通过 RPC 传播到所有参与的微服务分支。2.RM 拦截业务 SQL在执行更新前查询原始数据生成before image前镜像3.执行业务 ,更新数据库业务数据4.更新完成后查询更新后的数据生成after image后镜像更新完成后查询更新后的数据生成 after image后镜像5.在同一个本地数据库事务内写入 undo_log存放前后镜像 向 TC 申请全局锁6.拿到全局锁后提交本地数据库事务释放本地行锁、数据库连接后续根据结果分为2种情况执行A全局事务正常提交1.TM通知TC 全局事务提交2.TC下发commit 指令给所有 RM 分支3.RM收到commit异步任务批量删除当前分支的 undo_log立刻返回成功B全局事务回滚某分支失败1.TM通知TC 全局回滚2.TC下发rollback 指令给 RM3.RM查询undo_log对比after image 和 当前数据库数据防脏写校验4.如果数据没有被别的事务修改根据 before 镜像生成补偿 SQL 执行回滚5.回滚成功后删除 undo_log如果校验失败数据已被外部修改进入人工告警处理。AT 模式的全局锁与本地锁修改同一行数据的多个全局事务串行执行不能并发写 规则本地事务提交之前必须先拿到 TC 上该行记录的全局锁拿不到全局锁不允许提交本地事务不断重试超时直接回滚本地事务普通本地事务没有 GlobalTransactional直接操作数据库不受 Seata 全局锁控制可以修改数据会破坏隔离。缓存与数据库不同步问题更新 DB 和操作缓存是两个独立操作原子性无法保证只能做到最终一致性Cache Aside旁路缓存工业最常用先更新数据库再删除缓存。先删缓存再更新数据库会出现读请求在 DB 更新前命中旧数据写入缓存永久脏数据的并发问题