简单聊聊消息队列的事务补偿机制

转自:https://my.oschina.net/u/1589819/blog/1503241

因为一直学习与尝试负责公司的推送相关业务,包括整个应用的实现,其中就采用了基于消息队列的异步事件驱动模型来做解耦异步处理,所以就要去做了解一些相关的知识点,这边稍作总结,并整理一下消息补偿机制的一套简单实现的代码设计图。

采用基于消息队列的异步事件驱动模型来解决问题的时候,一个计较棘手的问题就是事务的一致性。

案例:现在用户发起一个创建订单的请求,如果我们是单系统架构,那么修改订单表,修改库存表可能都是在同一个事务中完成,所以轻而易举就达到了事物一致性原则,但是这不是我们要讨论的,所以就带过。现在微服务架构在互联网公司大火特火,热度未减,分布式是事务也成为了一个亟待解决的问题,阿里云GTS标榜如何让分布式事务更简单。

比如,用户发起一个创建订单的请求,首先在订单服务上生成了新的订单,同时还要去库存服务中减去库存,因为是分布式架构,所以库存扣减与订单创建可能是在两个遥远的机器上,如果想要通过本地事务来解决那几乎是不可能的,保证两个事务之间的状态一致性——订单创建成功,库存扣减失败,如何回滚订单?一直都是分布式架构中绕不开的挑战。

分布式架构中如何解决事务问题,在很多技术群都上都在讨论,比如dubbo , spring cloud等等。目前还没有接触到这方面相关知识,后续如果有幸参与,可做分享,本次想要聊的是假基于消息队列的异步事件驱动是如何解决如上的分布式问题,以及如何保证事务一致性。

事务一致性原则(ACID):

  • Atomicity - 原子性,改变数据状态要么是一起完成,要么一起失败
  • Consistency - 一致性,数据的状态是完整一致的
  • Isolation - 隔离线,即使有并发事务,互相之间也不影响
  • Durability - 持久性, 一旦事务提交,不可撤销

订单创建完成之后,发送一个createOrderEvent到消息队列中,由消息队列负责转发给订阅该消息的消费者进行处理。

好,这个时候如果消息消费 成功,但是库存不足,库存扣减失败,订单创建则不能成功,这个时候很好处理,由库存服务推送一个subInventoryFail给到订单服务,订单服务根据消息将订单转为失败状态。

1、从用户体验的角度来说,整个过程是异步的,所以对于用户的体验来说,就做不到“立马成功或立马失败”的效果。

2、从技术的角度来说,整个过程你不再关注同一个事物的问题,而是关注最终订单的状态是否一致。【注:从分布式事务<-->最终一致性】保证事务最终一致性,但是基于这种事件驱动达到最终一致,解耦事务的成功实施需要依赖几个因素。

a、消息的投递是否可靠。

b、消息的可靠性,例如订单服务已经成功创建订单,但是还没来得及发送消息就宕机或者各种原因,导致订单的状态不一致。

基于以上两点的考虑,我们使用了一种基于本地事务的方案来保证消息最终的一致性。

创建订单与创建消息事件都在本地事务中,属于同一个事务,可以保证订单表与消息事件表的数据一致性。发送消息到消息中间件,在事务提交之后发送。到了库存服务的时候,启动一个定时任务去扫描消息事件表,将未投递失败/消费 失败的消息进行消费,即补偿事务一致性。

定时任务的方案可能不是最佳的,可以稍作改定,比如采用阿里巴巴开源的Canal

公司目前也是采用这种架构来解决订单与库存问题。有网友的做法是保证消息投递的可靠性,我们则是保证消费的一致性,具体的文章点我>>

可以将消息队列的进行封装,做成了一个starter,代码设计上大致如图下:

@山茶果

原文地址:https://www.cnblogs.com/taozi32/p/11704823.html

时间: 2024-10-07 02:19:14

简单聊聊消息队列的事务补偿机制的相关文章

关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究[转]

1.XA XA是由X/Open组织提出的分布式事务的规范.XA规范主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接口.XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁.XA之所以需要引入事务管理器是因为,在分布式系统中,从理论上讲(参考Fischer等的论文),两台机器理论上无法达到一致的状态,需要引入一

计算机程序的思维逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列

本节介绍内存映射文件,内存映射文件不是Java引入的概念,而是操作系统提供的一种功能,大部分操作系统都支持. 我们先来介绍内存映射文件的基本概念,它是什么,能解决什么问题,然后我们介绍如何在Java中使用,我们会设计和实现一个简单的.持久化的.跨程序的消息队列来演示内存映射文件的应用. 基本概念 所谓内存映射文件,就是将文件映射到内存,文件对应于内存中的一个字节数组,对文件的操作变为对这个字节数组的操作,而字节数组的操作直接映射到文件上.这种映射可以是映射文件全部区域,也可以是只映射一部分区域.

Lua 下实现一个简单的消息队列

Lua 下实现一个简单的消息队列,如下简单的几条代码就可以了. local q1 = {} local q2 = {} -- 产生消息只需要 table.insert(q1, msg) -- 分发消息需要两层循环, 可以处理 dispatch 过程中产生的新消息 while q1[1] do q1,q2 = q2,q1 for i=1,#q2 do dispatch(q2[i]) q2[i] = nil end end

Spring + JMS + ActiveMQ实现简单的消息队列(监听器异步实现)

首先声明:以下内容均是在网上找别人的博客综合学习而成的,可能会发现某些代码与其他博主的相同,由于参考的文章比较多,这里对你们表示感谢,就不一一列举,如果有侵权的地方,请通知我,我可以把该文章删除. 1.jms-xml Spring配置文件 [html] view plain copy print? <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springf

ZWave 中的消息队列机制

文章主题   在我们的日常编程中,对消息队列的需求非常常见,使用一个简洁.高效的消息队列编程模型,对于代码逻辑的清晰性,对于事件处理的高效率来说,是非常重要的.这篇文章就来看看 ZWave 中是通过什么机制为我们提供了一个便捷的消息队列处理机制. 内容导航   消息队列是什么 我自己写的消息队列 ZWave 消息队列的结构 ZWave 消息队列的使用(初始化.存储消息.取出消息) 消息队列是什么   消息队列最主要特点是:存储消息,先进先出. 比如在典型的生产者-消费者编程模型中,先创建一个消息

消息队列设计精要【转】

消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一. 当今市面上有很多主流的消息中间件,如老牌的ActiveMQ.RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify.MetaQ.RocketMQ等. 本文不会一一介绍这些消息队列的所有特性,而是探讨一下自主开发设计一个消息队列时,你需要思考和设计的重要方面.过程中我们会参考这些成熟消息队列的很多重要思想. 本文首先会阐述什么时候你需要

消息队列设计精要(转)

消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的ActiveMQ.RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify.MetaQ.RocketMQ等.本文不会一一介绍这些消息队列的所有特性,而是探讨一下自主开发设计一个消息队列时,你需要思考和设计的重要方面.过程中我们会参考这些成熟消息队列的很多重要思想.本文首先会阐述什么时候你需要一个消

Python 番外 消息队列设计精要

消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的ActiveMQ.RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify.MetaQ.RocketMQ等.本文不会一一介绍这些消息队列的所有特性,而是探讨一下自主开发设计一个消息队列时,你需要思考和设计的重要方面.过程中我们会参考这些成熟消息队列的很多重要思想.本文首先会阐述什么时候你需要一个消

消息队列设计精要(转载)

消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的ActiveMQ.RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify.MetaQ.RocketMQ等.本文不会一一介绍这些消息队列的所有特性,而是探讨一下自主开发设计一个消息队列时,你需要思考和设计的重要方面.过程中我们会参考这些成熟消息队列的很多重要思想.本文首先会阐述什么时候你需要一个消