背景

在一个微服务架构的项目中,一个业务操作可能涉及到多个服务,这些服务往往是独立部署,构成一个个独立的系统。这种分布式的系统架构往往面临着分布式事务的问题。为了保证系统数据的一致性,我们需要确保这些服务中的操作要么全部成功,要么全部失败。通过使用RocketMQ实现分布式事务,我们可以协调这些服务的操作,保证数据的一致性。

功能原理

RocketMQ的分布式事务消息功能,在普通消息基础上,支持二阶段的提交。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。

整个事务消息的详细交互流程如下图所示:

1、生产者将消息发送至RocketMQ服务端。

2、RocketMQ服务端将消息持久化成功之后,向生产者返回Ack确认消息已经发送成功,此时消息被标记为"暂不能投递",这种状态下的消息即为半事务消息。

3、生产者开始执行本地事务逻辑。

4、生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:

  • 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。

  • 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。

5、在断网或者是生产者应用重启的特殊情况下,若服务端未收到生产者提交的二次确认结果,或服务端收到的二次确认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者集群中任一生产者实例发起消息回查。

6、生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。

7、生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。

注意问题

消息类型

事务消息仅支持在MessageType为Transaction的主题使用,即事务消息只能发送至类型为事务消息的主题中。

消息消费

RocketMQ事务消息保证生产者本地事务和下游消息发送事务的一致性,但不保证消息消费结果和上游事务的一致性。因此需要下游业务自行保证消息正确处理,建议消费端做好消费重试。

中间状态

RocketMQ事务消息一致性为最终一致性,即在消息提交到下游消费端处理完成之前,下游和上游事务之间的状态会不一致。因此,事务消息仅适合能接受异步执行的场景。

事务超时

RocketMQ事务消息的生命周期存在超时机制,即半事务消息被生产者发送服务端后,如果在指定时间内服务端无法确认提交或者回滚状态,则消息默认会被回滚。

示例代码

以下为RocketMQ 4.x版本事务消息示例代码,

import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt; import java.util.concurrent.*; public class RocketMqTransactionDemo {
public static void main(String[] args) throws Exception {
// 创建事务消息生产者
TransactionMQProducer producer = new TransactionMQProducer("transaction_producer");
producer.setNamesrvAddr("127.0.0.1:9876"); // 设置事务监听器
TransactionListener transactionListener = new MyTransactionListener();
producer.setTransactionListener(transactionListener); // 设置事务回查的线程池,可以不必设置,如果不设置也会默认生成一个
ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue <Runnable> (2000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("client-transaction-msg-check-thread");
return thread;
}
});
producer.setExecutorService(executorService); // 启动生产者
producer.start(); // 发送事务消息
Message message = new Message("transaction_topic", "test_tag", "test_key", "Hello RocketMQ".getBytes());
producer.sendMessageInTransaction(message, null); // 关闭生产者
producer.shutdown();
}
} /**
* 事务监听器
*/
class MyTransactionListener implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 执行本地事务操作
System.out.println("执行本地事务操作,消息内容:" + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE; // 提交事务,允许消费者消费该消息
// return LocalTransactionState.ROLLBACK_MESSAGE;// 回滚事务,消息将被丢弃不允许消费。
// return LocalTransactionState.UNKNOW;// 暂时无法判断状态,等待固定时间以后Broker端根据回查规则向生产者进行消息回查。
} @Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
// 检查本地事务状态
System.out.println("检查本地事务状态,消息内容:" + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE;
}
}

代码解释:

1、事务消息的生产者使用TransactionMQProducer创建。

2、MyTransactionListener作为事务监听器,实现了接口TransactionListener,该接口有两个方法,分别是:

  • executeLocalTransaction

    半事务消息发送成功后,执行本地事务的方法,具体执行完本地事务后,可以在该方法中返回以下三种状态:

    LocalTransactionState.COMMIT_MESSAGE: 提交事务,允许消费者消费该消息。

    LocalTransactionState.ROLLBACK_MESSAGE: 回滚事务,消息将被丢弃不允许消费。

    LocalTransactionState.UNKNOW: 暂时无法判断状态,等待固定时间以后RocketMQ服务端根据回查规则向生产者进行消息回查。

  • checkLocalTransaction

    二次确认消息没有收到,RocketMQ服务端回查生产者端事务结果的方法。回查规则:本地事务执行完成后,若RocketMQ服务端收到的本地事务返回状态为LocalTransactionState.UNKNOW,或生产者应用退出导致本地事务未提交任何状态。则RocketMQ服务端会向消息生产者发起事务回查,第一次回查后仍未获取到事务状态,则之后每隔一段时间会再次回查。

基于RocketMQ实现分布式事务的更多相关文章

  1. SpringCloud+RocketMQ实现分布式事务

    随着互联网公司的微服务越来越多,分布式事务已经成为了我们的经常使用的.所以我们来一步一步的实现基于RocketMQ的分布式事务.接下来,我们将要做的主题写出来. RocketMQ的分布式事务结构和说明 ...

  2. 谈谈分布式事务之二:基于DTC的分布式事务管理模型[下篇]

    [续上篇] 当基于LTM或者KTM的事务提升到基于DTC的分布式事务后,DTC成为了本机所有事务型资源管理器的管理者:此外,当一个事务型操作超出了本机的范 围,出现了跨机器的调用后,本机的DTC需要于 ...

  3. 基于Dubbo的分布式事务框架(LCN)

    原文地址:http://原文地址:https://github.com/1991wangliang/transaction 基于Dubbo的分布式事务框架(LCN) 该框架依赖Redis/dubbo/ ...

  4. 分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)

    本文描述spring boot基于Atomikos+DruidXADataSource分布式事务配置(100%纯动态),也就是增加.减少数据源只需要修改application.properties文件 ...

  5. 【RocketMQ】【分布式事务】使用RocketMQ实现分布式事务

    参考地址:https://blog.csdn.net/zyw23zyw23/article/details/79070044 视频地址:https://v.youku.com/v_show/id_XO ...

  6. 分布式事务(3)---RocketMQ实现分布式事务原理

    分布式事务(3)-RocketMQ实现分布式事务原理 之前讲过有关分布式事务2PC.3PC.TCC的理论知识,博客地址: 1.分布式事务(1)---2PC和3PC原理 2.分布式事务(2)---TCC ...

  7. 分布式事务(4)---RocketMQ实现分布式事务项目

    RocketMQ实现分布式事务 有关RocketMQ实现分布式事务前面写了一篇博客 1.RocketMQ实现分布式事务原理 下面就这个项目做个整体简单介绍,并在文字最下方附上项目Github地址. 一 ...

  8. 数据库内核——基于HLC的分布式事务实现深度剖析

    DTCC 2019 | 深度解码阿里数据库实现 数据库内核--基于HLC的分布式事务实现深度剖析-阿里云开发者社区 https://developer.aliyun.com/article/70355 ...

  9. DTCC 2019 | 深度解码阿里数据库实现 数据库内核——基于HLC的分布式事务实现深度剖析

    摘要:分布式事务是分布式数据库最难攻克的技术之一,分布式事务为分布式数据库提供一致性数据访问的支持,保证全局读写原子性和隔离性,提供一体化分布式数据库的用户体验.本文主要分享分布式数据库中的时钟解决方 ...

  10. RocketMQ实现分布式事务

    相关文章:http://www.uml.org.cn/zjjs/201810091.asp(深入理解分布式事务,高并发下分布式事务的解决方案) 三种分布式事务: 1.基于XA协议的两阶段提交 2.消息 ...

随机推荐

  1. C/C++ 实现Windows注册表操作

    Windows注册表(Registry)是Windows操作系统中用于存储系统配置信息.用户设置和应用程序数据的一个集中式数据库.它是一个层次结构的数据库,由键(Key)和值(Value)组成,这些键 ...

  2. MySQL 字符串与时间操作函数

    MariaDB [lyshark]> select Name,char_length(Name) from lyshark; -- 求字符串长度 +------------+---------- ...

  3. MAYSQL 2 DAY

    目录 MySQL day02 1.关于查询结果集的去重? 2.连接查询 2.2.连接查询的分类? 2.4.怎么避免笛卡尔积现象?当然是加条件进行过滤. 2.5.内连接之等值连接:最大特点是:条件是等量 ...

  4. CF131D Subway 题解

    题目传送门 前置知识 强连通分量 | 最短路 解法 考虑用 Tarjan 进行缩点,然后跑最短路. 缩点:本题的缩点有些特殊,基于有向图缩点修改而得,因为是无向图,所以在 Tarjan 过程中要额外记 ...

  5. google recaptcha 谷歌人机身份验证超详细使用教程,前端/后端集成说明

    壹 ❀ 引 在日常页面交互中,验证码使用是极为频繁的,登录注册验证,非机器人操作验证等等,它遍布于每一个网站.说到验证码实现,Goole Recaptcha是一个非常不错的选择,那么希望通过本文的使用 ...

  6. NC202589 魔法数字

    题目链接 题目 题目描述 牛妹给牛牛写了一个数字n,然后又给自己写了一个数字m,她希望牛牛能执行最少的操作将他的数字转化成自己的. 操作共有三种,如下: 1.在当前数字的基础上加一,如:4转化为5 2 ...

  7. CSS实现展开动画

    CSS实现展开动画 展开收起效果是比较常见的一种交互方式,通常的做法是控制display属性值在none和其它值之间切换,虽说功能可以实现,但是效果略显生硬,所以会有这样的需求--希望元素展开收起能具 ...

  8. flask+xlswriter+axios导出Excel

    flask后端 starttime = request.json.get('starttime') endtime = request.json.get('endtime') # 根据时间查询数据库数 ...

  9. CentOS 7 SSH连接超时自动断开解决方案

    用SSH登录到Linux的时候,由于默认的连接超时时间很短,经常断开! 1.修改文件 # vi /etc/ssh/sshd_config # vi /etc/ssh/sshd_config 找到 #C ...

  10. Java并发编程实例--12.使用线程工厂创建线程

    工厂模式是面向对象编程世界中最有用的设计模式. 它是一个创新型的模式,目标是开发一个对象,这个对象的任务是去创建其他类对象. 这样一来,如果我们想创建某些类的对象就不需要使用new关键字.好处有以下几 ...