Mq实现分布式事物

微服务中分布式事物的重要性

真实案列
刚刚入职新公司时,还记得当时上个产品生产环境报了一个bug。
场景
项目是微服务架构,App业务服务/积分服务。
问题: 用户注册送积分,偶现 用户注册成功,可积分未赠送
查找问题过程: jmeter 压力测试,抓日志,日志如下:
App服务日志
Mq实现分布式事物
文章图片
jf.png
App服务:注册日志,从日志查看可明显看出执行 insertAppUserSign 方法时间是 2018-07-11 15:39:20.455
积分服务日志
Mq实现分布式事物
文章图片
jf2.png
App服务:注册日志,从日志查看可明显看出执行 getAppUserByIds 方法时间是 2018-07-11 15:39:20.453
【Mq实现分布式事物】积分服务:判断用户是否存在。
//查询用户是否存在 List appUserIds = Lists.newArrayList(); appUserIds.add(requestDto.getAppUserId()); List appUserByIds = integralRewardMapper.getAppUserByIds(appUserIds); if (appUserByIds == null || appUserByIds.isEmpty()){ throw new RestException(ReturnCodeEnum.INVALID.code,ReturnCodeEnum.INVALID.msg); }

问题总结:具体原因可看出,因积分服务在为用户新增积分时,会判断用户是否存在。可从日志看App服务的用户在20.455s才入库,而积分服务在20.453s就已经在查询该用户是否存在了,那么该用户注册应该得到的积分确没有。这就是在多服务情况下容易出现的问题,以及非常经典订单与库存案例:订单下单了,库存仍然有,则会出现一个商品可能会被下单两次【秒杀问题】
利用MQ实现分布式事物
这里使用的RabbitMq,为什么使用Rabbit呢?还有Kafka,ActiveMq,RocketMq为什么不选择呢?
这里就简单说一下:kafka主要业务为处理日志这块,利用elk可以更好的处理庞大的日志信息。
RocketMq这是阿里研发的消息队列,当时还没有不知道,见笑了。ActiveMq相对于RabbitMq开源社区的活跃度不高。
利用RabbitMq (画图工具https://www.draw.io/)
Mq实现分布式事物
文章图片
mq.jpg
  • 1、事物发起方首先发送消息到MQ
  • 2、本地业务处理
  • 3、业务处理成功,将成功表示存入redis,业务处理失败,则跑出异常,事物回滚
  • 4、执行本地事物
  • 5、MQ消费端消费消息【需判断标识是否存在,如果不存在则说明业务需回滚,存在则进行消费
利用Rocket 4.3版本 支持分布式事物 (画图工具https://www.draw.io/)
Mq实现分布式事物
文章图片
rocket.jpg
  • 1、事务发起方首先发送 prepare(即发送Half消息) 消息到 MQ。
  • 2、在发送 prepare 消息成功后(即收到Half消息发送成功的回执消息) ,执行本地事务(业务系统自己的本地事物逻辑代码)。
  • 3、根据本地事务执行结果,返回给MQ发送方发送: commit 或者是 rollback。
  • 4、如果MQ发送方接收到的消息是: rollback,MQ 将删除该 prepare 消息不进行下发,如果是 commit 消息,MQ 将会把这个消息发送给 consumer 端。
  • 5、如果执行本地事务过程中,执行端挂掉,或者超时,MQ 将会不停的询问其同组的其他 producer 来获取状态。
  • 6、Consumer 端的消费成功机制有 MQ 保证。
参考
https://mp.weixin.qq.com/s/43wwC4lp77m4foVPEgTRlA
不停的发现,不停的学习

    推荐阅读