前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >业务处理成功,发送MQ失败?

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

作者头像
贪挽懒月
发布2022-11-18 15:56:22
7630
发布2022-11-18 15:56:22
举报
文章被收录于专栏:JavaEEJavaEE

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

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

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

场景复现

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

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

事务消息

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

kafka事务消息

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

RocketMQ事务消息
  • 流程:它是两阶段提交事务,可以很好地解决上面的问题。一阶段先发送一条half消息到MQ Server,此时这条消息对消费者是不可见的;接着执行业务逻辑;二阶段根据业务逻辑的执行结果,判断MQ的事务是提交还是回滚,如果提交,那么这条消息就可以被消费者消费了。
  • 补偿措施:如果根据业务逻辑对MQ事务执行提交或者回滚时因为超时等原因失败了,MQ Server会回调业务端的接口,通过这个接口去查询刚才的业务到底成功了没有,根据查询结果再决定MQ的事务要提交还是回滚。这个回调接口是需要我们自己去实现的。
其他方案
  • 新建一个表用来保存生产者生产的消息;
  • 在执行业务逻辑的方法里,不直接把消息发往MQ,而是先入库;
  • 这样可以保证这两个入库操作是同一个数据库事务;
  • 最后通过定时任务去查询库中的消息,发往MQ,发失败了还可以通过该任务重发
总结

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景复现
  • 事务消息
    • kafka事务消息
      • RocketMQ事务消息
      • 其他方案
      • 总结
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档