美文网首页分布式
谈谈分布式事务

谈谈分布式事务

作者: 修行者12138 | 来源:发表于2022-03-18 21:54 被阅读0次

    背景

    上游系统A,需要通过mq向下游系统B发送下单请求,B系统通过mq把订单号回传给A系统

    mysql事务与mq消息

    系统A在发送mq之前,有自己的mysql事务,如何处理mysql事务与mq消息?

    方案 执行顺序 说明
    方案一 1. 发送mq
    2. 开启事务
    3. CURD
    4. 提交事务
    如果CURD失败,mq无法撤销
    方案二 1. 开启事务
    2. CURD
    3. 发送mq
    4. 提交事务
    由于各种原因,提交事务可能失败,mq无法撤销
    方案三 1. 开启事务
    2. CURD
    3. 提交事务
    4. 发送mq
    提交事务后再发送mq,无法保证mq一定发送成功
    方案四 用rocketmq的事务消息 强依赖于rocketmq(如果不考虑后面更换mq,这个方案也可以)
    方案五 1. 开启事务
    2. CURD
    3. 向本地消息表插一行记录
    4. 提交事务
    5. 发送mq
    通过本地消息表,保证mq消息一定发送成功,从而达到最终一致性

    方案五的本地消息表,存储的是mq的topic、消息内容、状态等信息,除了需要新建表,还需要引入定时任务,具体流程如下


    image.png

    幂等

    mq消息有可能重复推送,因此消费者一定要做幂等。
    假设下单时,mq消息里只有商品id、商品数量,B系统重复消费到mq消息时,很难标识这两条消息是不是同一笔订单,因此最好是A系统产生一个唯一id,放到mq消息里。

    B系统的幂等实现如下

    image.png
    说明
    1. 如果同一个mq消息并发重复投递,请求2到的时候,请求1还没执行完,查不到uuid对应的下单记录,会重复执行下单逻辑,因此需要加上分布式锁。
    2. 请求2需要阻塞到请求1执行完成,然后返回请求1生成的订单号,因为这样才做到幂等(重复请求返回结果一致)。
    3. 如果不返回uuid,A系统拿到订单号,不知道对应哪一笔订单。

    B系统生成的订单号通过mq回传给A系统,也有可能重复投递,因此A系统也需要有幂等逻辑


    image.png

    如果分布式事务中,涉及到一些非常重要、敏感的接口,比如转钱,即使下游说已经做了幂等,上游最好不要100%信任,万一下游的幂等有bug呢。
    以本文的case为例,最好要求下游提供一个“根据uuid查询订单号”的接口,在重试的代码里,先调查询接口,查不到订单号再重试。

    相关文章

      网友评论

        本文标题:谈谈分布式事务

        本文链接:https://www.haomeiwen.com/subject/frngdrtx.html