使用消息队列来避免分布式事务

如果仔细观察生活的话,生活的很多场景已经给了我们提示。

比如在北京很有名的姚记炒肝点了炒肝并付了钱后,他们并不会直接把你点的炒肝给你,往往是给你一张小票,然后让你拿着小票到出货区排队去取。

为什么他们要将付钱和取货两个动作分开呢?原因很多,其中一个很重要的原因是为了使他们接待能力增强(并发量更高)。

还是回到我们的问题,只要这张小票在,你最终是能拿到炒肝的。同理转账服务也是如此,当用户A账户扣除1万后,

我们只要生成一个凭证(消息)即可,这个凭证(消息)上写着“让用户B账户增加 1万”,只要这个凭证(消息)能可靠保存,

我们最终是可以拿着这个凭证(消息)让用户B账户增加1万的,即我们能依靠这个凭证(消息)完成最终一致性。

1 如何可靠保存凭证(消息)

有两种方法:

1.1 业务与消息耦合的方式

用户A在完成扣款的同时,同时记录消息数据,这个消息数据与业务数据保存在同一数据库实例里(消息记录表表名为message);

上述事务能保证只要用户A账户里被扣了钱,消息一定能保存下来。

当上述事务提交成功后,我们通过实时消息服务将此消息通知用户B,用户B处理成功后发送回复成功消息,用户A收到回复后删除该条消息数据。

1.2 业务与消息解耦方式

上述保存消息的方式使得消息数据和业务数据紧耦合在一起,从架构上看不够优雅,而且容易诱发其他问题。为了解耦,可以采用以下方式。

1)用户A在扣款事务提交之前,向实时消息服务请求发送消息,实时消息服务只记录消息数据,而不真正发送,只有消息发送成功后才会提交事务;

2)当用户A扣款事务被提交成功后,向实时消息服务确认发送。只有在得到确认发送指令后,实时消息服务才真正发送该消息;

3)当用户A扣款事务提交失败回滚后,向实时消息服务取消发送。在得到取消发送指令后,该消息将不会被发送;

4)对于那些未确认的消息或者取消的消息,需要有一个消息状态确认系统定时去用户A系统查询这个消息的状态并进行更新。为什么需要这一步骤,

举个例子:假设在第2步用户A扣款事务被成功提交后,系统挂了,此时消息状态并未被更新为“确认发送”,从而导致消息不能被发送。

优点:消息数据独立存储,降低业务系统与消息系统间的耦合;

缺点:一次消息发送需要两次请求;业务处理服务需要实现消息状态回查接口。

2 如何解决消息重复投递的问题

还有一个很严重的问题就是消息重复投递,以我们用户A转账到用户B为例,如果相同的消息被重复投递两次,那么我们用户B账户将会增加2万而不是1万了。

为什么相同的消息会被重复投递?比如用户B处理完消息msg后,发送了处理成功的消息给用户A,正常情况下用户A应该要删除消息msg,但如果用户A这时候悲剧的挂了,

重启后一看消息msg还在,就会继续发送消息msg。

解决方法很简单,在用户B这边增加消息应用状态表(message_apply),通俗来说就是个账本,用于记录消息的消费情况,每次来一个消息,

在真正执行之前,先去消息应用状态表中查询一遍,如果找到说明是重复消息,丢弃即可,如果没找到才执行,同时插入到消息应用状态表(同一事务)

java消息队列mq_我爱java系列---【消息队列(rabbitmq)】相关推荐

  1. java 鉴权_我爱java系列之---【JWT实现微服务鉴权(一)】

    JWT介绍 JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. 一个JWT实际上就是一个字符串,它由三部分组成,头部.载荷与签 ...

  2. 我爱Java系列---【 maven依赖版本冲突的解决方法】

    我爱Java系列---[ maven依赖版本冲突的解决方法] 参考文章: (1)我爱Java系列---[ maven依赖版本冲突的解决方法] (2)https://www.cnblogs.com/hu ...

  3. 【Android 异步操作】Handler 机制 ( MessageQueue 消息队列的阻塞机制 | Java 层机制 | native 层阻塞机制 | native 层解除阻塞机制 )

    文章目录 一.MessageQueue 的 Java 层机制 二.MessageQueue 的 native 层阻塞机制 三.MessageQueue 的 native 层解除阻塞机制 三.Messa ...

  4. Java并发编程最佳实例详解系列

    Java并发编程最佳实例详解系列: Java并发编程(一)线程定义.状态和属性 Java并发编程(一)线程定义.状态和属性 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.在java语言中, ...

  5. java群发图文消息_使用Java语言开发微信公众平台(四)——图文消息的发送与响应...

    在上一篇文章中,我们实现了被关注回复与关键词回复功能.在用户关注的时候自动推送功能菜单,并根据用户输入的关键词,回复特定信息.但是,我们只能回复文本消息给用户,如何才回复一条图文消息呢?本周,我们一起 ...

  6. java 同步锁_死磕 java同步系列之自己动手写一个锁Lock

    问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...

  7. java 微服务实践 视频,全新JAVA微服为务实战Spring Boot系列视频教程 小马哥 JAVA微服务实践视频课程...

    全新JAVA微服为务实战Spring Boot系列视频教程 小马哥 JAVA微服务实践视频课程 ===============课程目录=============== ├─(1) 03Java 微服务实 ...

  8. java 栈_Java实现单链表、栈、队列三种数据结构

    作者:远航 cnblogs.com/yang-guang-zhang/p/13884023.html 一.单链表 1.在我们数据结构中,单链表非常重要.它里面的数据元素是以结点为单位,每个结点是由数据 ...

  9. 日常Java练习题(每天进步一点点系列)【含通知】

    提示:好多小伙伴反映,直接看到答案不太好,那我把答案的颜色设置为透明,答案位置还是在题目后面,需要鼠标选中才能看见(操作如下图),同时为了手机端的小伙伴(手机端也可以长按选中查看),我还会把所有答案放 ...

最新文章

  1. Eclipse使用gradle编译时,使用固定的jdk版本进行编译(修改gradle的jdk编译版本)
  2. python绘制动态模拟图-Python 模拟动态产生字母验证码图片功能
  3. SVM支持向量机详解
  4. RabbitMQ 死信/死信队列
  5. 你真的了解css像素嘛?
  6. oracle捕捉所有异常,如何捕获和处理特定的Oracle异常?
  7. flask route
  8. 【Vue.js 知识量化】基础语法
  9. IOS开发之把 Array 和 Dictionaries 序列化成 JSON 对象
  10. js去除字符串空格(空白符)
  11. coreldraw快速撤回_CorelDRAW操作技巧,教你CDR撤销操作方法与设置技巧
  12. 208个地级市总人口、城市和农村人口、城镇化率面板数据(2010-2019年)
  13. 写给情人,写给情人节,写给即将开始的新一年
  14. 自学Redis技术,如何在Java应用
  15. 硅谷最有权势的人:孙正义和他的愿景帝国
  16. 鸿蒙os第一批到第四批要多久,鸿蒙值得期待 鸿蒙OS系统适应计划曝光
  17. 如何使用Github学生包申请JET BRAINS
  18. 学日语、记单词是有规律的(转载)
  19. vue垂死挣扎系列(一)——vue-cli快速搭建
  20. webStorm 3.0配置使用主题背景色等

热门文章

  1. android 键盘 自动消失,Android 系统键盘怎么也不消失
  2. oracle查看日期是第几周,oracle查看日期是第几周-Oracle
  3. 【技术公开课】Redis从入门到实践
  4. 各大搜索引擎爬虫UA
  5. 美团基于知识图谱的剧本杀标准化建设与应用
  6. 交换机千兆和百兆对网速影响_交换机对网速的影响
  7. linux wine运行效率,Linux 使用 Wine 运行 TIM 简明教程
  8. Kubernetes 调度器实现初探
  9. 使用Aeon Timeline 2 for mac如何恢复丢失的文件
  10. html边框闪烁代码,纯css实现动态边框的示例代码