52.RocketMQ 事务
今天的博客有点多,因为前几天一直用笔记录,今天都补上了。后面的博客先停一段时间,后面还有dubbo、storm、kafka、solor、nginx、keepalived、fastdfs等内容,只是因为最近准备跳槽,停更一段时间,等到新公司后再继续更新。
场景1:支付宝转1w到余额宝,支付宝扣了1w,服务挂了怎么办?余额还没有加上
场景2:订单系统和库存系统如何保持一致
如果是本地的话很好解决
- begin transaction
update 支付宝 - 1w;
update 余额宝 + 1W;
end transaction - 用Spring的话,方法上加 @Transaction注释
那如果是跨系统的呢?该如何解决?
有一种思路是这样的:

- client发送转账请求给事务协调器
- 事务协调器先发送扣款请求给支付宝,返回执行结果(这时并没有提交)
- 事务协调器在发送加款请求给余额宝,返回执行结果(这时也没有提交)
- 事务协调器看两个执行结果都返回OK 就执行第四步,提交2和3没有提交的更新请求。
但是这个有个问题,那就是性能很受影响,主要卡在事务协调器这里。
RocketMQ的实现方式如下(图片来自网络):

支付宝先生成 扣款信息 --> 消息队列 --> 余额宝消费消息
发送消息:
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.client.producer.TransactionCheckListener;
import com.alibaba.rocketmq.client.producer.TransactionMQProducer;
import com.alibaba.rocketmq.common.message.Message; /**
* 发送事务消息例子
*
*/
public class TransactionProducer {
public static void main(String[] args) throws MQClientException, InterruptedException { TransactionCheckListener transactionCheckListener = new TransactionCheckListenerImpl();
TransactionMQProducer producer = new TransactionMQProducer("please_rename_unique_group_name");
// 事务回查最小并发数
producer.setCheckThreadPoolMinSize(2);
// 事务回查最大并发数
producer.setCheckThreadPoolMaxSize(2);
// 队列数
producer.setCheckRequestHoldMax(2000);
producer.setTransactionCheckListener(transactionCheckListener);
producer.start(); String[] tags = new String[] { "TagA", "TagB", "TagC", "TagD", "TagE" };
TransactionExecuterImpl tranExecuter = new TransactionExecuterImpl();
for (int i = 0; i < 100; i++) {
try {
Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes());
SendResult sendResult = producer.sendMessageInTransaction(msg, tranExecuter, null);
System.out.println(sendResult); Thread.sleep(10);
}
catch (MQClientException e) {
e.printStackTrace();
}
} for (int i = 0; i < 100000; i++) {
Thread.sleep(1000);
} producer.shutdown(); }
}
执行本地事务
import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.rocketmq.client.producer.LocalTransactionExecuter;
import com.alibaba.rocketmq.client.producer.LocalTransactionState;
import com.alibaba.rocketmq.common.message.Message; /**
* 执行本地事务
*/
public class TransactionExecuterImpl implements LocalTransactionExecuter {
private AtomicInteger transactionIndex = new AtomicInteger(1); @Override
public LocalTransactionState executeLocalTransactionBranch(final Message msg, final Object arg) {
int value = transactionIndex.getAndIncrement(); if (value == 0) {
throw new RuntimeException("Could not find db");
}
else if ((value % 5) == 0) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
else if ((value % 4) == 0) {
return LocalTransactionState.COMMIT_MESSAGE;
} return LocalTransactionState.UNKNOW;
}
}
服务器回查客户端(这个功能在开源版本中已经被咔掉了,但是我们还是要写,不然报错)
import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.rocketmq.client.producer.LocalTransactionState;
import com.alibaba.rocketmq.client.producer.TransactionCheckListener;
import com.alibaba.rocketmq.common.message.MessageExt; /**
* 未决事务,服务器回查客户端
*/
public class TransactionCheckListenerImpl implements TransactionCheckListener {
private AtomicInteger transactionIndex = new AtomicInteger(0); @Override
public LocalTransactionState checkLocalTransactionState(MessageExt msg) {
System.out.println("server checking TrMsg " + msg.toString()); int value = transactionIndex.getAndIncrement();
if ((value % 6) == 0) {
throw new RuntimeException("Could not find db");
}
else if ((value % 5) == 0) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
else if ((value % 4) == 0) {
return LocalTransactionState.COMMIT_MESSAGE;
} return LocalTransactionState.UNKNOW;
}
}
到这就完了,为什么只介绍发送不介绍接收呢?因为一旦消息提交到MQ就不用管了, 要相信MQ会把消息送达consumer,如果消息未能被成功消费的话,那么Producer也会回滚
如何保证分布式系统的全局性事务?
因为阿里在3.2.6版本后,砍掉了消息回查的功能,也就是consumer端是否成功消费,Producer端并不知道,所以如果要保证全局性事务,我们要有自己的实现机制:

52.RocketMQ 事务的更多相关文章
- rocketmq事务消息
rocketmq事务消息 参考: https://blog.csdn.net/u011686226/article/details/78106215 https://yq.aliyun.com/art ...
- RocketMQ源码分析之从官方示例窥探:RocketMQ事务消息实现基本思想
摘要: RocketMQ源码分析之从官方示例窥探RocketMQ事务消息实现基本思想. 在阅读本文前,若您对RocketMQ技术感兴趣,请加入RocketMQ技术交流群 RocketMQ4.3.0版本 ...
- RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)
在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...
- RocketMQ事务消息实现分析
这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...
- RocketMQ 事务消息
RocketMQ 事务消息在实现上充分利用了 RocketMQ 本身机制,在实现零依赖的基础上,同样实现了高性能.可扩展.全异步等一系列特性. 在具体实现上,RocketMQ 通过使用 Half To ...
- 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务
搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...
- 【转】RocketMQ事务消费和顺序消费详解
RocketMQ事务消费和顺序消费详解 转载说明:该文章纯转载,若有侵权或给原作者造成不便望告知,仅供学习参考. 一.RocketMq有3中消息类型 1.普通消费 2. 顺序消费 3.事务消费 顺序消 ...
- rocketmq事务消息入门介绍
说明 周五的时候发了篇:Rocketmq4.3支持事务啦!!!,趁着周末的时候把相关内容看了下,下面的主要内容就是关于RocketMQ事务相关内容介绍了. 说明: 今天这篇仅仅是入门介绍,并没有涉及到 ...
- RocketMQ事务消息学习及刨坑过程
一.背景 MQ组件是系统架构里必不可少的一门利器,设计层面可以降低系统耦合度,高并发场景又可以起到削峰填谷的作用,从单体应用到集群部署方案,再到现在的微服务架构,MQ凭借其优秀的性能和高可靠性,得到了 ...
随机推荐
- php闭包bindTo方法用法
从手册知道,Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域. 创建并返回一个 匿名函数, 它与当前对象的函数体相同.绑定了同样变量,但可以绑定不同的对象,也可 ...
- jdeveloper12.1.3的安装与卸载
jdeveloper12.1.3的安装步骤:1>安装jdk7.0 2>在命令行中输入:cd C:\Program Files\Java\jdk1.7.0_60\bin 3>命令行安装 ...
- 数据挖掘潜规则zz
声明:本文指的是做数据挖掘这行,不是数据仓库 我干这行有几年了,见了很多人,干了很多公司,爆一爆这个行业的状况吧……让后来人有所了解,也让猎头挖人挖的有点方向,起码和candidates聊天的时候不至 ...
- python获取参数
argparse是python的一个命令行参数模块,可以解析命令行参数,生成帮助. 示例: #!/usr/bin/python from argparse import ArgumentParser ...
- java grpc简单例子
原文地址:http://blog.csdn.net/jek123456/article/details/53465033 用eclipse新建一个maven项目,Id信息如下 <groupId& ...
- metasploit-数据库支持
db_status db_disconnect db_connect 用户名:口令@服务器地址:端口/数据库名称 createdb msf4 -E UTF8 -T template0 -o msf3 ...
- CLOB 和 BLOB
An SQL CLOB is a built-in type that stores a Character Large Object as a column value in a row of a ...
- Open XML操作Excel导入数据
项目中发现使用OleDb(using System.Data.OleDb)相关对象处理Excel导入功能,不是很稳定经常出问题,需要把这个问题解决掉.项目组提出使用OpenXML来处理Excel的导入 ...
- CentOS6.3安装MySQL5.5
1.查看系统是否安装了MySQL 使用命令: #rpm -qa | grep mysql 2.卸载已安装的MySQL 卸载mysql命令如下: #rpm -e --nodeps mysql-libs ...
- win10 数字许可证激活被 KMS激活覆盖
打开cmd(管理员身份),依次执行以下命令: slmgr/upk slmgr/ckms slmgr/rearm 重启设备后联网登录Microsoft账号,转设置-激活-疑难解答,windows会找到与 ...