RocketMQ事务消息实战
我们以一个订单流转流程来举例,例如订单子系统创建订单,需要将订单数据下发到其他子系统(与第三方系统对接)这个场景,我们通常会将两个系统进行解耦,不直接使用服务调用的方式进行交互。其业务实现步骤通常为:
1、A系统创建订单并入库。
2、发送消息到MQ。
3、MQ消费者消费消息,发送远程RPC服务调用,完成订单数据的同步。
1、方案一
方案弊端:
1、如果消息发送成功,在提交事务的时候JVM突然挂掉,事务没有成功提交,导致两个系统之间数据不一致。
2、由于消息是在事务提交之前提交,发送的消息内容是订单实体的内容,会造成在消费端进行消费时如果需要去验证订单是否存在时可能出现订单不存在。
3、消息发送可以考虑异步发送。
方案二:
由于存在上述问题,在MQ不支持事务消息的前提条件下,可以采用下面的方式进行优化。
然后在控制器层,使用异步发送,将消息发送,并在消息发送成功后,更新待发送状态为已发送。
然后通过定时任务,扫描待发送,结合创建时间的记录(小于当前时间5分钟的消息待发送记录),进行消息发送。
方案弊端:
1、消息有可能重复发送,但在消费端可以通过唯一业务编号来进行去重设计。
2、实现过于复杂,为了避免 极端情况下的消息丢失,需要使用定时任务。
方案三:基于RocketMQ4.3版本事务消息
额外需要实现事务会查监听器:TransactionListener,其实例代码:
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 java.util.concurrent.ConcurrentHashMap; @SuppressWarnings("unused")
public class OrderTransactionListenerImpl implements TransactionListener { private ConcurrentHashMap<String, Integer> countHashMap = new ConcurrentHashMap<>(); private final static int MAX_COUNT = 5; @Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
//
String bizUniNo = msg.getUserProperty("bizUniNo"); // 从消息中获取业务唯一ID。
// 将bizUniNo入库,表名:t_message_transaction,表结构 bizUniNo(主键),业务类型。
return LocalTransactionState.UNKNOW;
} @Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
Integer status = 0;
// 从数据库查查询t_message_transaction表,如果该表中存在记录,则提交,
String bizUniNo = msg.getUserProperty("bizUniNo"); // 从消息中获取业务唯一ID。
// 然后t_message_transaction 表,是否存在bizUniNo,如果存在,则返回COMMIT_MESSAGE,
// 不存在,则记录查询次数,未超过次数,返回UNKNOW,超过次数,返回ROLLBACK_MESSAGE if(query(bizUniNo) > 0 ) {
return LocalTransactionState.ROLLBACK_MESSAGE;
} return rollBackOrUnown(bizUniNo);
} public int query(String bizUniNo) {
return 1; //select count(1) from t_message_transaction a where a.biz_uni_no=#{bizUniNo}
} public LocalTransactionState rollBackOrUnown(String bizUniNo) {
Integer num = countHashMap.get(bizUniNo); if(num != null && ++num > MAX_COUNT) {
countHashMap.remove(bizUniNo);
return LocalTransactionState.ROLLBACK_MESSAGE;
} if(num == null) {
num = new Integer(1);
} countHashMap.put(bizUniNo, num);
return LocalTransactionState.UNKNOW; } }
TransactionListener 实现要点:
executeLocalTransaction:
该方法,主要是设置本地事务状态,该方法与业务方代码在一个事务中,例如OrderServer#createMap中,只要本地事务提交成功,该方法也会提交成功。
故在这里,主要是t_message_transaction添加一条记录,在事务会查时,如果存在记录,就认为是该消息需要提交。
checkLocalTransaction:
该方法主要是告知RocketMQ消息是否需要提交还是回滚,如果本地事务表(t_message_transaction)存在记录,则认为提交,如果不存在,可以设置会查次数,如果指定次数内还是未查到消息,则回滚,否则返回未知,rocketmq会按一定的频率回查事务,当然回查次数也有限制,默认为5次,可配置。
RocketMQ事务消息实战的更多相关文章
- 关于 RocketMQ 事务消息的正确打开方式 → 你学废了吗
开心一刻 昨晚和一哥们一起吃夜宵,点了几瓶啤酒 不一会天空下起了小雨,哥们突然道:糟了 我:怎么了 哥们:外面下雨了,我老婆还在等着我去接她 他给了自己一巴掌,说道:真他妈不是个东西 我心想:哥们真是 ...
- RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)
在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...
- RocketMQ事务消息实现分析
这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...
- RocketMQ 事务消息
RocketMQ 事务消息在实现上充分利用了 RocketMQ 本身机制,在实现零依赖的基础上,同样实现了高性能.可扩展.全异步等一系列特性. 在具体实现上,RocketMQ 通过使用 Half To ...
- rocketmq事务消息
rocketmq事务消息 参考: https://blog.csdn.net/u011686226/article/details/78106215 https://yq.aliyun.com/art ...
- 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务
搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...
- rocketmq事务消息入门介绍
说明 周五的时候发了篇:Rocketmq4.3支持事务啦!!!,趁着周末的时候把相关内容看了下,下面的主要内容就是关于RocketMQ事务相关内容介绍了. 说明: 今天这篇仅仅是入门介绍,并没有涉及到 ...
- RocketMQ事务消息学习及刨坑过程
一.背景 MQ组件是系统架构里必不可少的一门利器,设计层面可以降低系统耦合度,高并发场景又可以起到削峰填谷的作用,从单体应用到集群部署方案,再到现在的微服务架构,MQ凭借其优秀的性能和高可靠性,得到了 ...
- RocketMQ之四:RocketMq事务消息
事务消息 通过消息的异步事务,可以保证本地事务和消息发送同时执行成功或失败,从而保证了数据的最终一致性. 发送端执行如下几步: 发送prepare消息,该消息对Consumer不可见 执行本地事务(如 ...
随机推荐
- HDU2966 In case of failure(浅谈k-d tree)
嘟嘟嘟 题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方.(\(n \leqslant 1e5\)) 这就是k-d tree入门题了. k-d tre ...
- P1754 球迷购票问题
题目背景 盛况空前的足球赛即将举行.球赛门票售票处排起了球迷购票长龙. 按售票处规定,每位购票者限购一张门票,且每张票售价为50元.在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值1 ...
- MySql常用命令集Mysql常用命令showdatabases;显示数据库createdatab
MySql 常用命令集 Mysql常用命令 show databases; 显示数据库 create database name; 创建数据库 use databasename; 选择数据库 drop ...
- Django rest framework集成微博第三方登录
Django restframework 集成第三方登录(微博.微信.QQ等) 友情链接 python-social-auth-app官方文档 微博开放者平台 QQ开放者平台 准备工作 1.注册微博开 ...
- Objective-C @executable_path、@loader_path和@rpath
工程配置中,有三个路径和库的加载息息相关: 1.@executable_path 可执行文件的路径,例如/Applications/WeChat.app/Contents/MacOS. 2.@load ...
- FreeRTOS学习笔记--任务优先级
FreeRTOSConfig.h 中的常量configMAX_PRIORITIES的值就是任务优先级的最大数值,这个数值可以按照自己的需要改动,当然值越大,内核对内存的开销就越大,一般设置一个满足自己 ...
- ubuntu 安装json
命令行中输入:sudo apt-get install libjsoncpp-dev
- at android.view.Surface.unlockCanvasAndPost(Native Method)
at android.view.Surface.unlockCanvasAndPost(Native Method) 在绘制动画特效的时候点击back键会报以上异常. 主要原因:当点击back按钮时A ...
- Java实现几种常见排序方法
日常操作中常见的排序方法有:冒泡排序.快速排序.选择排序.插入排序.希尔排序,甚至还有基数排序.鸡尾酒排序.桶排序.鸽巢排序.归并排序等. 以下常见算法的定义 1. 插入排序:插入排序基本操作就是将一 ...
- 火狐浏览器 system error code 1722 rpc服务器不可用和谷歌浏览器的插件application/x-print-ladop不支持
今天要实现打印的功能,但是火狐浏览器总是出现提示:火狐浏览器 system error code 1722 rpc服务器不可用 后来发现主要是系统服务中的一个windows服务没有打开导致的. 将wi ...