背景

电商中有这样的一个场景:

  1. 下单成功之后送积分的操作,我们使用mq来实现
  2. 下单成功之后,投递一条消息到mq,积分系统消费消息,给用户增加积分

我们主要讨论一下,下单及投递消息到mq的操作,如何实现?每种方式优缺点?

方式一

step1:start transaction
step2:生成订单
step3:投递消息到mq
step4:commit transaction

这种方式是将发送消息放在了事务提交之前,可能存在的问题:

step3发生异常

导致step4失败,下单失败,直接影响到下单业务

step4发生异常,其他step成功

下单失败,消息投递成功,给用户增加了积分

方式二

我们将发送消息放到事务之后进行:
step1:start transaction
step2:生成订单
step3:commit transaction
step4:投递消息到mq

可能会出现的问题:
step4发生异常,其他step成功

导致下单成功,投递消息失败,用户未增加积分

上面两种是比较常见的做法,也是最容易出错的。

方式三

step1:start transaction
step2:生成订单
step3:本地库中插入一条需要发送消息的记录t_msg_record
step3:commit transaction
step5:新增一个定时器,轮询t_msg_record,将待发送的记录投递到mq中

这种方式借助了数据库的事务,业务和消息记录作为了一个原子操作,业务成功之后,消息日志必定是存在的。解决了前两种方式遇到的问题。如果我们的业务系统比较单一,可以采用这种方式。

对于微服务化的情况,上面这种方式不是太好,每个服务都需要上面的操作;也不利于扩展。

方式四

增加一个消息服务消息库,负责消息的落库、将消息发送投递到mq。

step1:start transaction
step2:生成订单
step3:当前事务库插入一条日志:生成一个唯一的业务id(bus_id),将bus_id和订单关联起来保存到当前事务所在的库中
step4:调用消息服务:携带bus_id,将消息先落地入库,此时消息的状态为待发送状态,返回消息id(msg_id)
step5:commit transaction
step6:如果上面都成功,调用消息服务,将消息投递到mq中;如果上面有失败的情况,则调用消息服务取消消息的发送

能想到上面这种方式,已经算是有很大进步了,我们继续分析一下可能存在的问题:

  1. 系统中增加了一个消息服务,下单操作依赖于该服务,业务对改服务依赖性比较高,当消息服务不可用时,整个业务将不可用。
  2. 若step6失败,消息将处于待发送状态,此时业务方需要提供一个会查接口(通过bus_id查询),验证业务是否执行成功;消息服务需新增一个定时任务,对于状态为待发送状态的消息做补偿处理,检查一下业务是否处理成功;从而确定消息是投递还是取消发送
  3. step4依赖于消息服务,如果消息服务性能不佳,会导致当前业务的事务提交时间延长,容易产生死锁,并导致并发性能降低。我们通常是比较忌讳在事务中做远程调用处理的,远程调用的性能和时间往往不可控,会导致当前事务变为一个大事务,从而引发其他故障。

方式五

在以上方式中,我们继续改进,进而出现了更好的一种方式:

step1:生成一个全局唯一业务消息id(bus_msg_id),调用消息服务,携带bus_msg_id,将消息先落地入库,此时消息的状态为待发送状态,返回消息id(msg_id)
step2:start transaction
step3:生成订单
step4:当前事务库插入一条日志(将step3中的业务和bus_msg_id关联起来)
step5:commit transaction
step6:分2中情况:如果上面都成功,调用消息服务,将消息投递到mq中;如果上面有失败的情况,则调用消息服务取消消息的发送

方式五和方式四对比,比较好的一个地方:将调用消息服务,消息落地操作,放在了事务之外进行,这点小的改进其实算是一个非常好的优化。

总结

  1. 若我们的系统系统比较小比较单一简单,建议采用方式三
  2. 若我们的系统采用微服务的方式,建议使用方式五
  3. 你们的系统中如何发送消息的,大家可以留言,我们一起讨论,一起进步。

mq系列整个内容

  1. 聊聊mq的使用场景
  2. 聊聊业务系统中投递消息到mq的几种方式
  3. 如何确保投递消息一定成功?
  4. 聊聊消息消费的几种方式
  5. 如何确保消息至少消费一次
  6. 如何保证消息消费的幂等性

可以关注公众号:路人甲Java,获取年薪50万课程,获取最新文章。

聊聊业务系统中投递消息到mq的几种方式的更多相关文章

  1. [转]Windows系统中监控文件复制操作的几种方式

    1. ICopyHook 作用: 监视文件夹和打印机移动,删除, 重命名, 复制操作. 可以得到源和目标文件名. 可以控制拒绝操作. 缺点: 不能对文件进行控制. 只对Shell文件操作有效, 对原生 ...

  2. Windows系统中监控文件复制操作的几种方式

    http://blog.sina.com.cn/s/blog_4596beaa0100lp4y.html 1. ICopyHook 作用: 监视文件夹和打印机移动,删除, 重命名, 复制操作. 可以得 ...

  3. 现代IM系统中的消息系统架构 - 架构篇

    https://mp.weixin.qq.com/s/sAlI8MCIKUSj5KbcT3W-Lw 现代IM系统中的消息系统架构 - 架构篇 原创: 木洛 云栖社区 1周前

  4. C#中关于增强类功能的几种方式

    C#中关于增强类功能的几种方式 本文主要讲解如何利用C#语言自身的特性来对一个类的功能进行丰富与增强,便于拓展现有项目的一些功能. 拓展方法 扩展方法被定义为静态方法,通过实例方法语法进行调用.方法的 ...

  5. C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌

    1.  IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...

  6. Latex中如何设置字体颜色(3种方式)

    Latex中如何设置字体颜色(三种方式)   1.直接使用定义好的颜色 \usepackage{color} \textcolor{red/blue/green/black/white/cyan/ma ...

  7. Velocity中加载vm文件的三种方式

    Velocity中加载vm文件的三种方式: a.  加载classpath目录下的vm文件 /** * 初始化Velocity引擎 * --VelocityEngine是单例模式,线程安全 * @th ...

  8. Mybatis中使用association进行关联的几种方式

    这里以一对一单向关联为例.对使用或不使用association的配置进行举例.  实体类: @Data @ToString @NoArgsConstructor public class IdCard ...

  9. Action中取得request,session的四种方式

    Action中取得request,session的四种方式 在Struts2中,从Action中取得request,session的对象进行应用是开发中的必需步骤,那么如何从Action中取得这些对象 ...

随机推荐

  1. win10 安装cuda和cudnn

    首先通过nvidia-smi 查看自己的显卡驱动对应的cuda版本. 参考:https://blog.csdn.net/qq_40212975/article/details/89963016 再去官 ...

  2. linux-在指定路径下查询文件夹是否存在

    我们常常在Linux下去查找文件 find / -name 'test.py' # 在根目录下查找名为test.py的文件 但是如果用查找文件的方式去查找文件夹的话,是查不到的 find / -max ...

  3. IT兄弟连 HTML5教程 CSS3揭秘 CSS3属性5

    9  透明属性 元素透明也是我们常用的样式,在CSS2中使用滤镜属性opacity实现透明效果.现在有了CSS3的rgba属性,就不用这么麻烦了,当然这也得要浏览器支持才行.通常我们定义颜色都是用十六 ...

  4. Python三级菜单作业实现

    数据结构: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, '汽车之家':{}, ...

  5. jquery使用on()方法绑定的事件被执行多次的问题

    jQuery用on()方法绑定了事件之后,在代码执行过程中,可能会遇到事件被多次执行的情况. 本来以为是事件冒泡的问题,后来发现是on()方法的特性引起的问题. 简单还原一下问题的场景 这里简单还原一 ...

  6. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU特性那些事(2)- RT1052DVL6性能实测(CoreMark)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列MCU的性能. 在前面的文章 i.MXRTyyyy微控制器概览 里,痞子衡给大家简介过恩智浦半导体在2 ...

  7. 深入selenium模块基础操作

    selenium模块的基本操作 一.模拟浏览器 ​ 谷歌.Firefox.Safari等浏览器 browser=webdriver.Chrome() browser=webdriver.Firefox ...

  8. Java学习 1.2——简述JVM,JRE,JDK的关系

    在上一节中,我们了解了JVM相关的知识,有兴趣的话可以先去看一下: Java学习 1.1——(JVM介绍)Java为什么能够跨平台? 这个篇主要分享的是JRE,JDK,JVM三者的区别,简言之: JD ...

  9. 平时代码中用不到设计模式?Are you kidding me?

    引子 平时我是个反应非常慢的人.有多慢呢?大概是两年前有次团队内部开会时,我听到同学说平时代码中用不到设计模式,我当时没有回答.两年后我终于反应过来了:“Are you kidding me?我每天都 ...

  10. Angular中使用bootstrap样式

    Angular中使用bootstrap样式 Angular中引入bootstrap的方法   方法1:在Angular.json中的styles数组中添加bootstrap路径 如下所示: " ...