zoukankan      html  css  js  c++  java
  • 分布式事物的设计与实践

    分布式事物设计与实践

    数据一致性定义

    • 任何人
    • 任何时间
    • 任何地点
    • 任何接入方式
    • 任何服务
    • 数据都是一致的

    数据不一致产生的原因

    • 数据分散在多处
      • 多个DB
      • DB和缓存
    • 二手交易平台案例
      • 用户,交易,商品等功能

    分布式事物产生的原因

    刚开始是一个单体进程

    image.png

    经过演变,单体式服务演变成微服务,每个服务都是单独的进程

    image.png

    在用户请求量大的时候,为了缓解数据库的压力,添加了分布式缓存

    image.png

    分布式事物案例

    电商平台购买商品

    下单->减库存->支付

    image.png

    这就是分布式事物问题,当APP要买东西,这个操作会涉及到多个服务,意味着要操作多个数据库,这样本地事物就无法保证数据的一致性,所以就产生了分布式事物问题.

    分布式事物场景

    • 电商下单场景
      • 下单
      • 发送消息到MQ
    • 一致性保证
      • 本地事物
        • 下单操作
        • 发送MQ消息操作
        • 放进一个本地事物

    上述做法有什么问题?

    image.png

    问题:如果发送消息超时了,你是不知道MQ的返回结果是成功和失败的,,timeout这操作不是一个原子的

     

    分布式事物分类

    • 刚性分布式事物
      • 强一致性
      • XA模型
      • CAP
        • CP
    • 柔性分布式事物
      • 最终一致性
      • CAP,BASE理论
        • AP

    刚性分布式事物

    满足传统事物特性

    ACID( Atomicity-原子性, Consistency-一致性,Isolation-隔离性,Durability-持久性)

    XA模型

    • XA是X/Open CAE Specification(Distributed Transaction Processing)模型中定义,XA规范由AP,RM,TM组成
    • 其中应用程序(Application Program简称AP),AP定义事物边界(定义事物开始和结束)并访问边界事物内的资源
    • 资源管理器(Resource Manager简称RM),RM管理计算机共享的资源,资源及数据库等
    • 事物管理器(Transaction Manager,简称TM),负责管理全局事物,分配事物唯一标识,监控事物的执行进度,并负责事物的提交,,回滚,失败恢复等

    image.png

    2PC(两阶段提交-XA规范标准实现)

    • 案例
      • 组织爬山
    • 过程
      • 二阶段提交,是XA规范的标准实现
      • TM发起prepare投票
      • RM都同意后,TM再发起Commit
      • Commit 过程出现宕机等异常,节点服务重启后,根据XA recover 再次进行commit补偿
    • 缺点
      • 同步阻塞模型
      • 数据库资源锁定时间过长
      • 全局锁(隔离级别-串行化),并发低
      • 不适合长事物场景

    image.png

    柔性分布式事物

    • CAP
      • 分布式环境下P一定需要,CA权衡折中
    • BASE理论
      • Basically Available-基本可用
      • Soft state 柔性状态
      • Eventual consistency 最终一致性
    • 架构思考
      • 柔性事物是对XA协议的妥协,他通过降低强一致性要求,从而降低数据库资源锁定时间,提升可用性
    • 架构经典实现
      • TCC模型
      • Saga模型

     

    TCC模型

    • Try-confirm-cancel
    • TCC模型完全交由业务实现,每个子业务都需要实现Try-Confirm-cancel接口,对业务侵入大
      • 资源锁定交由业务方
    • try
      • 尝试执行业务,完成所有检查,预留必要的业务资源
    • confirm
      • 真正执行业务,不再做业务检查
    • Cancel
      • 释放Try阶段预留的业务资源
    • 案例
      • 汇款服务,收款服务案例
        • A用户向B用户汇款500元
      • 汇款服务
        • try
          • 检查A账户的有效性,及查看A账户的状态是否为"转账中"或者"冻结"
          • 检查A账户余额是否充足
          • 从A账户中扣减500元,并将状态设置为转账中
          • 预留扣减资源,将从A往B账户转账500元这个事件存入消息或者日志中
        • confirm
          • 不做任何操作
        • cancel
          • A账户增加500元
          • 从日志或者消息中,释放扣减资源
      • 收款服务
        • try
          • 检查B账户是否有效
        • confirm
          • 读取日志或消息,B账户增加500元
          • 从日志或者消息中,释放扣减资源
        • cancel
          • 不做任何操作

    Saga模型

    • 起源于1987年Hector & Kenneth发表的论文Sagas
    • Saga模型把一个分布式事物拆分为多个本地事物,每个本地事物都有相应的执行模块和补偿模块(对应TCC中的confirm和cancel)
    • 当Saga事物中任意一个本地事物出错时,可以通过调用相关的补偿方法恢复之前的事物,到达事物最终一致性
    • 当每个Saga子事物T1,T2,....TN都有对应的补偿定义C1,C2,....CN-1,那么Saga系统可以保证
      • 子事物序列T1,T2,.....TN得以完成(最佳情况)
      • 或者序列T1,T2,...TJ,CJ-1,..., C2,C1,0<J<N,得以完成
    • Saga隔离性
      • 业务层控制并发
        • 在应用层加锁
        • 应用层预先冻结资源等
    • Saga恢复方式
      • 向后恢复,补偿所有已完成的事物,如果任意子事物的失败
      • 向前恢复,重试失败的事物,假设每个子事物最终都会成功

     

    刚性分布式事物VS柔性分布式事物

     

    刚性事物(XA)

    柔性事物

    业务改造

    回滚

    支持

    实现补偿接口

    一致性

    强一致(CP)

    最终一致性(AP)

    隔离性

    原生支持

    实现资源锁定接口

    并发性能

    严重衰退

    略微衰退

    适合场景

    短事物,并发较低

    长事物,高并发

    我们如何实践

    • 问题通用解决思路
      • 解决这个问题本身
      • 让问题本身消失
        • 圆珠笔笔芯漏油解决
    • 圆珠笔笔芯在写2W次就开始漏油,如果要解决这个问题本身,那么就是加入更好的材料,更高端的技术,如果是让问题本身消失呢,就是固定一个次数,让它只能写1.5W次就没油开始丢弃,这样的两种办法
    • 首选是让问题本身消失,次选是解决这个问题本身
    • 方案一:从业务场景消除分布式事物
      • 思路:核心业务先处理,其他业务异步处理
    • 方案二:柔性分布式事物

    柔性分布式事物实践

    • 通用处理思路
      • 本地事物-->短事物
      • 分布式事物-->长事物
      • 转变成多个短事物
      • 案例
        • A[下单]->B[减库存]->C[支付]
          • A->DB1
          • B->DB2
          • C->DB3
          • A/B/C都成功
          • A/B成功,C失败
            • 补偿
    • 业务场景
      • 异步场景
        • 基于MQ消息驱动分布事物
      • 同步场景
        • 基于异步补偿分布

    异步场景分布式事物设计

    异步场景

    商品交易

    下单,支付

    image.png

    方案一:业务方提供本地操作成功回查功能

      • 事物消息:MQ提供类似X/Open XA的分布式事物功能,通过MQ事物消息能达到分布式事物的最终一致
      • 半消息:暂不投递的消息,发送方已将消息成功发送到了MQ服务端,但是服务端未收到生产者对该消息的二次确认,此时该消息被标记成"暂不能投递"状态,处于该种状态下的消息即半消息
      • 消息回查:由于网络闪断,生产者应用重启等原因,导致某条事物消息的二次确认丢失,MQ服务端通过扫描发现某条消息长期处于半消息时,主要主动向消息生产者询问该消息的最终状态(Commit或Rollback),即消息回查
    • MQ分布式事物设计方案

    image.png

    • MQ分布式事物消息设计
      • MQ事物消息设计事物消息作为一种异步确保型事物,将两个事物分支通过MQ进行异步解耦,MQ事物消息的设计流程同样借鉴了两阶段提交理论,整体交互流程如上图
      1. 事物发起方首先发送prepare消息到MQ
      2. 在发送prepare消息成功后执行本地事物
      3. 根据本地事物执行结果返回commit或rollback
      4. 如果消息是rollback,MQ将删除该prepare消息,不进行下发,如果是commit消息,MQ会将消息发送给consumer端
      5. 如果执行本地事物过程中,执行端挂掉,或者超时,,MQ服务器端将不停的询问producer来获取事物状态
      6. consumer端的消费成功机制有MQ保证
    • 成本:
      • MQ需要支持半消息
      • MQ需要提供消息遍历
      • 业务方需要提供回查接口
    • 业务方接入步骤

    image.png

    • 优点
      • 通用
    • 缺点
      • 业务方需要提供回查接口,对业务侵入大
      • 发送消息非幂等
      • 消费端需要处理幂等

     

    方案二:本地事物消息表

    • 本地操作和发送消息通过本地事物强一致性
      • 本地事物操作表
      • 本地事物消息表
        • mqMessages(msgid,content,topic,status)

    image.png

    • 发送端消息不幂等
      • At least once (最少发一次)
      • Once Only (只发一次)
      • At more once(最多发一次)
    • 消费端处理消息幂等
      • 分布式锁
    • A->B->C
      • A/B成功,C失败
        • 记录错误日志
        • 报警
        • 人工介入
    • 优点
      • 业务入侵小

    相比于提供消息回查接口(RockectMQ)来说,实际异步场景还是本地消息事物表使用的比较多

     

    同步场景分布式事物设计

    • 同步场景
      • 首页推荐商品列表
        • 商品信息
        • 用户信息
        • 社交信息
      • 购买商品
        • 下单->A
        • 减库存->B
        • 支付->C

    image.pngimage.png

    通过业务逻辑层驱动

    • 解决方案
      • 基于异步补偿的分布式事物
      • 架构设计的三大关键点

    image.png

    开始记录调用请求的参数,如果失败后基于参数做补偿接口,接口需要保证幂等性

    • 总体架构设计

    image.png

    场景:A下单,B减库存,C支付,在调用接口的时候,A先走Proxy存入事物ID,状态,参数等信息,然后执行本地事物,接着B,C走同样的流程如果都成功,那么事物状态改成2,也就是成功,如果在C失败的时候可以更具参数,事物ID对A,B进行补偿

    业务逻辑层Proxy设计(基于AOP实现)

      • 逻辑层调用上加上事物注解@Around("execution(**(..)) && @annotation(TX)")
      • Proxy在真正业务逻辑被调用之前,生成一个全局唯一TXID标示事务组,TXID保存在ThreadLocal变量中,方法开始前写入,完成后清除,并向远端数据库写入TXID并把事务组制成开始状态
      • 业务逻辑层调用数据访问层之前,通过RPCProxy代理记录,当前调用请求参数
      • 如果业务正常,调用完成后,当前方法的调用记录删除或者存档
      • 如果业务异常,查询调用链反向补偿

    image.png

    • 数据访问层设计
      • 原子接口
      • 补偿接口
        • 谁来提供?
          • 业务方提供
        • 幂等性保证
          • 采用本地资源锁,锁定唯一资源
      • 基于原则接口方法,在方法名加注解标注补偿方法名
      • @Compensable(cancelMethod = "cancelRecord")

    image.pngimage.png

    • 分布式事物补偿服务
      • 事物组表(数据库表TDB)    
        • 记录事物组状态
        • txid state timestamp
      • 事物调用组表(数据库表TDB)
        • 记录事物组内的每一次调用,以及相关参数
        • txid actionid callmethod pramatype params
      • 补偿策略
        • 调用执行失败,修改事物组状态
        • 分布式事物补偿服务异步执行补偿

    分布式事物成功案例

    • 二手交易创建订单事务组正常流程
      • 锁库存->减红包->创建订单
    • 代理层透明记录调用请求参数
      • 记录事物域的开始与结束
      • 在所有远程调用成功时
      • 对业务逻辑不做侵入

    image.png

    分布式事物失败案例

    • 二手交易创建订单事务组异常流程
      • 微服务数据访问层失败,代理更改事务组状态
      • 微服务业务正常执行
      • 事物补偿服务异步执行补偿

    image.png

    好了,到这里分布式事物也就写完了..休息一下,,哎,又到了找工作的时候了,有需要可以联系我

  • 相关阅读:
    [LeetCode]Word Break
    [LeetCode]singleNumber
    [LeetCode]Palindrome
    新浪博客无法访问
    C++基础之顺序容器
    C++基础之IO类
    [LeetCode]Restore IP Addresses
    [LeetCode]Maximal Rectangle
    [LeetCode]Reverse Linked List II
    ACM 树形数组
  • 原文地址:https://www.cnblogs.com/flower-dance/p/14567024.html
Copyright © 2011-2022 走看看