RocketMQ事务性消息
mq事务介绍
mq事务消息流程
- 生产者发送消息到mq,消息状态为:SEND_OK。此消息是消费者不可见(消费者无法消费此条消息)
- 执行本地任务:成功则返回COMMIT_MESSAGE,此时消费者可消费此条消息。失败则返回ROLLBACK_MESSAGE,此时删除mq的此条消息
- 如果消息一定时间后没有被确认(COMMIT_MESSAGE)也没有被删除(ROLLBACK_MESSAGE),则mq回调一个方法,主动确认本地事务是否成功,主动要求确认消息状态。
1、配置文件
2、生产者
1、生产者配置
package com.gofun.customer.mqTrans; import com.gofun.customer.mq.RocketMqProducerProperties;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.concurrent.*; @Configuration
@EnableConfigurationProperties(RocketMqProducerProperties.class)
@ConditionalOnProperty(prefix = "rocketmq.producer", name = "iseffect", havingValue = "true")
public class RocketMqTransConfig {
@Autowired
private RocketMqProducerProperties rocketMqProperties; private final int corePoolSize = 2;//消费最小线程数
private final int maximumPoolSize = 5;//消费最大线程数
private final long keepAliveTime = 100;//线程活跃时间
private final TimeUnit timeUnit = TimeUnit.SECONDS;//keepAliveTime时间单位
private final int capacity = 2000;//保存任务的队列容量 @Bean
@ConditionalOnProperty(prefix = "rocketmq.producer", name = "type", havingValue = "transaction")
public TransactionMQProducer transactionMQProducer() throws MQClientException {
TransactionMQProducer transactionMQProducer = new TransactionMQProducer(rocketMqProperties.getGroupName()); ExecutorService executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit,
new ArrayBlockingQueue<Runnable>(capacity), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("client-transaction-msg-check-thread");
return thread;
}
});
transactionMQProducer.setNamesrvAddr(rocketMqProperties.getNamesrvAddr());
transactionMQProducer.setExecutorService(executorService);
transactionMQProducer.start();
return transactionMQProducer;
} }生产者发送工具类
package com.gofun.customer.mqTrans; import com.alibaba.fastjson.JSON;
import com.gofun.customer.mq.RocketMqProducerProperties;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class RocketMqTransProducer {
@Autowired
private TransactionMQProducer transactionMQProducer;
@Autowired
private RocketMqProducerProperties rocketMqProperties; public void setListener(TransactionListener listener) {
transactionMQProducer.setTransactionListener(listener);
transactionMQProducer.setSendMsgTimeout(10000);
} public SendResult send(String topic, String tag, Object obj) {
Message msg = new Message(topic, tag, getBody(obj));
SendResult sendResult = null;
try {
sendResult = transactionMQProducer.sendMessageInTransaction(msg, null);
} catch (Exception e) {
}
return sendResult;
} public SendResult send(String tag, Object obj) {
Message msg = new Message(rocketMqProperties.getTopicName(), tag, getBody(obj));
SendResult sendResult = null;
try {
sendResult = transactionMQProducer.sendMessageInTransaction(msg, null);
} catch (Exception e) {
}
return sendResult;
} private byte[] getBody(Object obj) {
String body = null;
if(obj == null){
return null;
}
if(obj instanceof String){
body = (String) obj;
}else{
body = JSON.toJSONString(obj);
}
return body.getBytes();
} }2、本地事务和超时mq回调方法
package com.gofun.customer.controller.test; import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component; import java.util.Random; @Component
public class TestTransactionListener implements TransactionListener {
private static boolean transStatus = true; /**
* 执行本地事务
*
* @param message
* @param o
* @return
*/
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
System.out.println("用一个随机数模拟本地任务执行成功或失败");
Random random = new Random();
transStatus = random.nextBoolean();
if (transStatus) {
System.out.println("执行本地任务成功。。。。。。");
return LocalTransactionState.COMMIT_MESSAGE;
}
System.out.println("执行本地任务失败。。。。。");
return LocalTransactionState.ROLLBACK_MESSAGE;
} /**
* mq长时间收不到提交消息,会执行此方法,检查本地事务是否成功
* @param messageExt
* @return
*/
@Override
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
System.out.println("获取本地任务执行成功或失败");
if (transStatus) {
System.out.println("判断本地任务成功。。。。");
return LocalTransactionState.COMMIT_MESSAGE;
}
System.out.println("判断本地任务失败。。。。");
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
- 实现接口TransactionListener
- executeLocalTransaction 方法内执行本地事务,并且判断事务是否成功,成功返回LocalTransactionState.COMMIT_MESSAGE,失败返回:LocalTransactionState.ROLLBACK_MESSAGE;
- LocalTransactionState.ROLLBACK_UNKNOW 是中间状态,该消息正在检查中,等待检查结果后执行上述两个状态
- checkLocalTransaction 方法是mq 长时间处于UNKNOW 状态时会调用此方法,主动请求确认消息状态。
3、发送事务消息
1、引入发送事务消息的工具类
@Autowired
private RocketMqTransProducer rocketMqProducer;
@Autowired
private TestTransactionListener testTransactionListener;2、发送消息
rocketMqProducer.setListener(testTransactionListener);
SendResult sendResult = rocketMqProducer.send("testTag", "测试mq发送消息。。。。");
if (sendResult != null) {
SendStatus sendStatus = sendResult.getSendStatus();
System.out.println("发送消息返回:" + sendStatus.toString());
} else {
System.out.println("发送消息失败");
}
3、消费者
消费者与非事务性消费者相同见:https://www.cnblogs.com/happydreamzjl/p/12022412.html
4、消费者消费情况
- 可看到本地任务成功时消费者消费了消息,本地任务失败时没有消费消息(消息没有发送成功)
转自:https://blog.csdn.net/Cy_LightBule/article/details/88891844
https://www.jianshu.com/p/5260a2739d80
RocketMQ事务性消息的更多相关文章
- RocketMQ事务性消息及持久化
TransactionProducer(事务消息): 在分布式系统中,我们时常会遇到分布式事务的问题,除了常规的解决方案之外,我们还可以利用RocketMQ的事务性消息来解决分布式事务的问题.Rock ...
- rocketmq总结(消息的高可用、中间件选型)
rocketmq总结(消息的高可用.中间件选型) 参考: https://blog.csdn.net/meilong_whpu/article/details/76922456 http://blog ...
- JMS - 事务性消息
JMS 事务遵从发送操作与接收操作相互分离的约定.下图显示的是一个事务性发送,其中一组消息要么能够保证全部到达消息服务器,要么连一条消息也不能保证到达消息服务器.从发送者的角度来看,JMS 提供者为这 ...
- RocketMQ源码 — 九、 RocketMQ延时消息
上一节消息重试里面提到了重试的消息可以被延时消费,其实除此之外,用户发送的消息也可以指定延时时间(更准确的说是延时等级),然后在指定延时时间之后投递消息,然后被consumer消费.阿里云的ons还支 ...
- 聊一聊顺序消息(RocketMQ顺序消息的实现机制)
当我们说顺序时,我们在说什么? 日常思维中,顺序大部分情况会和时间关联起来,即时间的先后表示事件的顺序关系. 比如事件A发生在下午3点一刻,而事件B发生在下午4点,那么我们认为事件A发生在事件B之前, ...
- RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)
在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...
- RocketMQ事务消息实现分析
这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...
- RocketMQ之消息幂等
幂等(idempotent.idempotence)是一个数学与计算机学概念,常见于抽象代数中. 在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同. 首先我们了解一下什么是 ...
- rocketmq总结(消息的顺序、重复、事务、消费模式)
rocketmq总结(消息的顺序.重复.事务.消费模式) 参考: http://www.cnblogs.com/wxd0108/p/6038543.html https://www.cnblogs.c ...
随机推荐
- kmp next数组的模板
string s; int Next[MAX]; int len; void get_next() { ,j=-; Next[i]=j;//初始化,next[0]=-1:-1表示没有前缀等于后缀. ; ...
- shell选项和参数
- redis系统管理命令
exists 和 del exists key:判断一个key是否存在,存在返回1,否则返回0. del key:删除某个key,或是一系列key type 和 keys type key:返回某个k ...
- servlet 实践
基础 当Servlet引擎收到一个请求,它将请求所有的细节汇编到一个HttpServletRequest对象.细节包括请求头部.URI.查询字符串和任意发送的参数等等.类似地,它初始化一个处理响应头部 ...
- cnblogs添加打赏
上图上真相 1.进入后台设置---文件 2.上传你的支付宝和微信收款码(注意图片格式为bmp格式) 2.还是上图的位置,选择设置选项,找到博客侧边栏公告(支持HTML代码)(支持JS代码) 3.将如下 ...
- c++后台开发面试常见知识点总结(五)场景设计
搜索引擎的实现,会用到哪些重要的数据结构 设计实现一个HTTP代理服务器 / web服务器 / FTP服务器/ 设计实现cache缓存web服务器的网页访问记录 把一个文件快速下发到100w个服务器 ...
- python中map的排序以及取出map中取最大最小值
map排序: 1.按key排序: items=dict.items() items.sort() sorted(dict.items(),key=lambda x:x[0],reverse=False ...
- hdu 4826 Labyrinth(简单dp)
Description 度度熊是一只喜欢探险的熊,一次偶然落进了一个m*n矩阵的迷宫,该迷宫只能从矩阵左上角第一个方格开始走,只有走到右上角的第一个格子才算走出迷宫,每一次只能走一格,且只能向上向下向 ...
- vue登录页和主页路由配置问题
登录页和主菜单首页是同一级的,都是用一个router-view,对于home页面里还有菜单,这里边还可以再增加一个router-view,那么在配置时候就是在home的路径增加个children路径配 ...
- HTML5: HTML5 Canvas
ylbtech-HTML5: HTML5 Canvas 1.返回顶部 1. HTML5 Canvas <canvas> 标签定义图形,比如图表和其他图像,您必须使用脚本来绘制图形. 在画布 ...
