美文网首页
业务处理成功,发送MQ失败?

业务处理成功,发送MQ失败?

作者: 贪挽懒月 | 来源:发表于2022-11-12 22:02 被阅读0次

    记得上次面试官问了我一个问题:

    • 面试官:你说你们项目用到了MQ,那么你往MQ发消息是在你业务事务提交之前还是之后呢?

    • 我:……

    那接下来分析一下这个问题。

    场景复现

    比如有个抢购,用户服务点击抢购,订单服务先返回排队中,订单服务处理完了之后肯定是通过MQ异步通知去支付的。现在的问题是,发MQ告诉用户抢去付款这个操作是在订单相关操作(比如扣库存,订单入库等)的事务提交之前还是之后呢?如果是之前,那如果事务回滚了就会出现用户付了钱但是订单没入库的情况;如果是之后,那就可能会出现订单入库了但是没通知用户去付款的情况。

    简言之,就是要让数据库操作和发送MQ是在同一个事务内!

    事务消息

    可能有人想到了,这不就是事务消息嘛!没错,不过不同的MQ事务消息也有所不同。

    kafka事务消息

    kafka事务类似数据库事务,就是一条消息要发往多个分区的时候,它可以保证发往的这多个分区同时成功或者失败,这种事务显然不能解决上面的问题。

    RocketMQ事务消息
    • 流程:它是两阶段提交事务,可以很好地解决上面的问题。一阶段先发送一条half消息到MQ Server,此时这条消息对消费者是不可见的;接着执行业务逻辑;二阶段根据业务逻辑的执行结果,判断MQ的事务是提交还是回滚,如果提交,那么这条消息就可以被消费者消费了。
    • 补偿措施:如果根据业务逻辑对MQ事务执行提交或者回滚时因为超时等原因失败了,MQ Server会回调业务端的接口,通过这个接口去查询刚才的业务到底成功了没有,根据查询结果再决定MQ的事务要提交还是回滚。这个回调接口是需要我们自己去实现的。

    其他方案

    • 新建一个表用来保存生产者生产的消息;
    • 在执行业务逻辑的方法里,不直接把消息发往MQ,而是先入库;
    • 这样可以保证这两个入库操作是同一个数据库事务;
    • 最后通过定时任务去查询库中的消息,发往MQ,发失败了还可以通过该任务重发

    总结

    RocketMQ的两阶段提交事务可以解决这个问题,但是每个场景我们都需要写对应的回调接口;先入库再通过定时任务去发消息这种方案可能就会有一点点的延时,即定时任务执行的频率就是消息消费的延时时长,比如你5秒执行一次,那么消息入库后最多就需要5秒钟后才会被查出来去消费。

    相关文章

      网友评论

          本文标题:业务处理成功,发送MQ失败?

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