分布式 事务概念

  • 一个业务操作跨多个数据库、服务才能完成,但必须保证业务的原子性,要么同成功,要么同失败,这就是分布式系统下的事务。

    Seata的XA模式是怎么保证事务安全的?

    image.png

  • Seata事务管理有三个重要的角色:

    • TC :事务协调者,维护全局和分支事务的状态,协调全局事务提交或回滚
    • TM:事务管理者,定义全局事务的范围、开始全局事务、提交或回滚全局事务。
    • RM:资源管理者 ,管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
  • XA是基于数据库事务来完成的,执行过程分为两个阶段,
    • 第一阶段当事务方法被执行,事务管理者感知到就向事务协调者申请开启全局事务,各个线程就去执行具体的分支事务,当具体的分支事务需要去操作数据库时,事务管理者就会调用资源管理者的事务操作,资源管理者就向事务协调者注册对应的事务分支,当所有的事务分支都注册完成后,资源管理者统一去执行sql,执行完不提交,继续持有数据库锁,并向事务协调者报告执行结果,当所有的资源管理者都执行完成后,
    • 进入第二阶段,事务管理者就告诉事务协调者事务操作完成了,事务协调者就拿着资源管理者报告的所有结果判断到低是提交事务还是回滚事务。
  • XA的优点和缺点:

    • 优点:
      • 事务的强一致性,满足ACID原则。
      • 常用数据库都支持,实现简单,并且没有代码侵入
    • 缺点:
      • 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差
      • 依赖关系型数据库实现事务

        Seata的AT模式是怎么保证事务安全的?

        image.png
  • AT模式的执行流程也分为两个阶段:

    • 第一个阶段,当事务管理者感知到事务方法被执行了,就向事务协调者请求开启全局事务,并且调用分支方法到资源管理器中申请分支事务处理的资源,资源管理器就会向事务协调者注册事务分支,然后执行sql并 记录一个undolog日志,提交事务,释放数据库行锁,最后向事务协调者报告事务执行的状态。
    • 第二个阶段,事务管理者感知到所有的分支事务都执行完成后,向事务协调者汇报 ,事务协调者就去检测所有的分支事务执行状态,决定是提交还是回滚。如果是提交就删除undolog日志;回滚的话就基于undolog日志进行数据恢复,恢复后再删除日志文件。
  • AT模式下产生的脏写问题?
    • 现在有两个事务,一个事务A和一个事务B,当事务A的分支事务获取到数据库锁,对数据进行修改了,然后就提交事务释放数据库 锁了,但事务A并没有结束,这个时候事务B进来也对这个数据进行了修改并且修改成功释放锁了,这个时候事务A有一个分支事务执行失败了,进行全局事务回滚,就把事务B修改的结果给覆盖了,事务B就修改了个寂寞。
  • AT模式下产生的脏写问题如何解决?
    • 解决思路就是引入了全局锁的概念。在释放DB锁之前,先拿到全局锁。避免同一时刻有另外一个事务来操作当前数据。
  • AT模式的优缺点?

    • 优点:
      • 一阶段完成直接提交事务,释放数据库资源,性能比较好
      • 利用全局锁实现读写隔离
      • 没有代码侵入,框架自动完成回滚和提交
    • 缺点:
      • 两阶段之间属于软状态,属于最终一致
      • 框架的快照功能会影响性能,但比XA模式要好很多

        Seata的TCC模式

  • TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复,需要实现三个方法:

    • Try:资源的检测和预留
    • Confirm:提交事务,要求Try成功就一定要能成功
    • Cancel:回滚释放资源
  • TCC模式只适用于一些特定场景下的事务操作,比如扣减用户余额的业务等,他也分为两个阶段,第一个阶段进行资源预留,报告预留状态;第二阶段资源协调器就根据整体预留状态决定是提交资源还是回滚释放资源。
  • TCC模式的优点和缺点:
    • 优点:无需生成快照,不用使用全局锁,性能好,不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库。
    • 缺点:有代码倾入,需要人员自己编写代码,还需考虑提交事务和回滚失败的情况,做好幂等处理。
  • TCC模式的空回滚
    • 就是有一个分支事务还没Try锁定资源就卡住了,超过了时间就开始第二阶段的回滚释放资源操作了,但是没有资源给他回滚,这就是空回滚。
    • 我们在执行cancel操作之前,先判断一下try执行没有,没有就空回滚。
  • TCC模式的业务悬挂
    • 就是前面都已经卡超过时间空回滚了,现在你不卡了又继续来Try锁定资源,你锁定了但是这个事务都走完了,现在没法提交事务和回滚事务了,资源就没法释放了, 这就是业务悬挂。
    • 我们应该在Try之前先判断一下是不是已经执行过cancel了,都执行过了你就别去Try再锁定资源了。避免悬挂。

最终一致性

image.png
消息的最终一致性他能保证消息的最终能达到一致,但是他的一致性是最差的,适用于不紧急的一些事务操作,比如用户付款以后生成订单,那这个时候他会在订单表中,添加一条记录,并且还会有一个消息表,来存储未发送的消息,他会有一个定时器来定时给MQ中发送未成功处理的消息,当MQ中的某消息被消费了,那么就会给我们的消息表中给这条消息改变状态,来区分成功处理的消息和没处理的消息。这就是可靠消息最终一致性
存在问题:幂等性问题,当消费消息以后发送的改变状态的请求被吃掉了,那么这个时候就会出现幂等问题,我们一般通过非自旋的分布式锁来解决。并且当这条消息被消费手动提交ack

最大努力通知

  • 最大努力通知通常用于支付场景下,当用户开始支付的时候,实际上是和支付宝或者微信进行对接的,我们的app是无法知道当前这个用户是否已经付款了的,用户付款之后,app虽然不知道,但是支付宝或者微信他们知道,那么他在收到钱之后,他们会通过回调机制通知我们的系统开始进行下一个逻辑操作
  • 支付宝或者微信他会基于一定策略来通知我们,用一个依次递增时间来像我们发起通知
  • 同时微信支付宝也会提供一个接口,用于我们的app主动的去查询用户的支付情况。