微服务架构-分布式消息中间件-091:RocketMQ-RocketMQ解决分布式事务问题

1 rocketmq解决分布式事务问题概述

课程安排:

  1. 什么是分布式事务?分布式事务最大思想
  2. RocketMQ与Rabbitmq解决分布式事务区别
  3. RocketMQ解决分布式事务最大的核心思想
  4. 基于RocketMQ实战解决分布式事务问题

2 rocketmq分布式事务问题简单回顾

分布式事务产生背景:rpc远程调用 多个不同服务之间通讯需要保证数据一致性的问题;存在多个数据源,每个数据源事务互不影响。
在这里插入图片描述

3 分布式事务最终一致性的核心思想

分布式领域中名词:
强一致性:读取数据不允许出现脏读;要求同步速度非常快或者采用锁的机制;
弱一致性:允许读取的数据为原来的脏数据;
最终一致性:在分布式系统中,因为数据之间同步通过网络实现通讯,短暂的数据延迟是允许的,但是最终数据必须要一致。数据同步延迟通过补偿(手动或者自动)解决。

举例:充值200电信话费,支付宝显示该笔订单已经扣款成功200,在电信app客户端订单中显示未支付。
解决方法:人工补偿,用订单号调用支付宝接口查询付款结果,手动补偿

4 回顾rabbitmq解决分布式事务的bug

在订单与派单系统中,因为订单系统可能发生各种变化,派单系统相对稳定,解决分布系统核心主要在订单系统。
rabbitmq解决分布式事务方案:
在这里插入图片描述
如果补单队列也挂的情况下,订单数据可能会丢失,但是能够成功派单,这种情况只能手动补偿。

5 rocketmq解决分布式事务思路

解决分布式事务的核心,必须先确保订单系统的事务能够百分百成功执行,如果该事务执行成功,就开始发送派单消息;如果该事务回滚的情况下,就不发送派单消息。
解决分布式事务核心思路:确保第一个事务一定先执行成功。

Rocketmq解决分布式事务的核心思路:

  1. 生产者向Broker(MQ服务器端)发送派单消息设置为半消息,该消息不可以被消费者消费;
  2. 执行本地的事务,将本地执行事务结果提交或者回滚告诉Broker;
  3. Broker获取到本地事务的结果,如果是提交的话,将该半消息设置为允许被消费者消费,如果本地事务执行失败的情况下,将该半消息直接从Broker中移除;
  4. 如果本地事务没有将结果及时通知给Broker,这时候Broker会主动定时(默认60s)查询本地事务结果(最多重试15次);
  5. 本地事务结果实际上就是一个回调方法,根据自己业务场景封装本地事务结果;
    为什么设置半消息:因为没有被订单系统的本地事务确认
    在这里插入图片描述

6 实战手写rocketmq核心代码

核心代码

@Service
public class ProducerService {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public String saveOrder() {
        // 提前生成订单userId
        String orderId = System.currentTimeMillis()+"";
        /**
         * 1.提前生成我们的半消息
         * 2.半消息发送成功之后,再执行本地事务
         */
        OrderEntity orderEntity = createOrder(orderId);
        String msg = JSONObject.toJSONString(orderEntity);
        MessageBuilder<String> stringMessageBuilder = MessageBuilder.withPayload(msg);
        stringMessageBuilder.setHeader("msg", msg);
        Message message = stringMessageBuilder.build();
        // 半消息,该消息不允许被消费者消费
        rocketMQTemplate.sendMessageInTransaction("mayiktProducer",
                "orderTopic", message, null);
        return orderId;
    }

    public OrderEntity createOrder(String orderId) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setName("每特教育第六期平均就业薪资破10万");
        orderEntity.setOrderCreatetime(new Date());
        // 价格是300元
        orderEntity.setOrderMoney(300d);
        // 状态为 未支付
        orderEntity.setOrderState(0);
        Long commodityId = 30L;
        // 商品id
        orderEntity.setCommodityId(commodityId);
        orderEntity.setOrderId(orderId);
        return orderEntity;
    }
}

7 rocketmq事务监听处理

@Slf4j
@Component
@RocketMQTransactionListener(txProducerGroup = "mayiktProducer")
public class SyncProducerListener implements RocketMQLocalTransactionListener {
    @Resource
    private OrderMapper orderMapper;
    @Autowired
    private TransationalUtils transationalUtils;

    /**
     * 执行订单的事务
     *
     * @param msg
     * @param arg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {

        MessageHeaders headers = msg.getHeaders();
        Object object = headers.get("msg");
        if (object == null) {
            return null;
        }
        String orderMsg = (String) object;
        OrderEntity orderEntity = JSONObject.parseObject(orderMsg, OrderEntity.class);
        TransactionStatus begin = null;
        try {
            begin = transationalUtils.begin();
            int result = orderMapper.addOrder(orderEntity);
            transationalUtils.commit(begin);
            if (result <= 0) {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
            // 告诉Broker可以消费该消息
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            if (begin != null) {
                transationalUtils.rollback(begin);
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }
        return null;
    }

    /**
     * 提供给Broker定时检查
     *
     * @param msg
     * @return
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        MessageHeaders headers = msg.getHeaders();
        Object object = headers.get("msg");
        if (object == null) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        String orderMsg = (String) object;
        OrderEntity orderEntity = JSONObject.parseObject(orderMsg, OrderEntity.class);
        String orderId = orderEntity.getOrderId();
        // 直接查询数据库
        OrderEntity orderDbEntity = orderMapper.findOrderId(orderId);
        if (orderDbEntity == null) {
            return RocketMQLocalTransactionState.UNKNOWN;
        }
        return RocketMQLocalTransactionState.COMMIT;
    }
}

8 断点调试rocketmq核心代码

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值