三事务型MQ的最终一致性事务方案--1RocketMQ事务消息的发送与提交
三 事务型MQ的最终一致性事务方案--1RocketMQ事务消息的发送与提交
该方案,在MQ事务最终一致性方案的基础上,使用RocketMQ提供的事务消息功能。其简化了非事务型MQ最终一致性方案的流程。如下:
流程如下:
事务消息的发送与commit/rollback阶段:
1 producer发送half消息给broker(此时不能消费);
2 服务端响应;
3 执行本地事务---executeLocalTransaction;
4 根据本地事务执行情况,commit或者rollback;
事务消息的补偿阶段:
1 如果broker长时间没有收到本地事务执行状态,会向producer发起回查事务状态的操作;
2 producer收到请求,检查本地事务执行状态---checkLocalTransaction;
3 根据本地事务的回查结果,执行commit或者rollback------补偿,用在producer发送commit/rollback操作时,发生超时或者失败的情况
具体开发流程如下:
producer端:
step1:在controller中,定义响应request的方法{
1 执行相应的业务流程;
2 生成事务消息的唯一业务id(snowFlake);
3 组装业务信息(包括事务唯一id)到消息体---方便消费端进行幂等消费;
4 调用producer发送事务prepare的half消息;
}
/** 注意:
通常开发过程中,在controller中调用service服务时,开启事务,事务执行成功后,向MQ发送half事务消息;
executeLocalTransaction方法,只执行事务信息的本地持久化操作;
在回查方法checkLocalTransaction中,只查询事务消息*/
ste2:实现TransactionListener创建事务信息监听器,并实现executeLocalTransaction(执行本地事务方法)和checkLocalTransaction(检查事务执行状态){
/**该方法完成两个任务:
1 向本地事务消息数据库添加记录;2 设置本地事务的状态,建议返回LocalTransactionState.UNKNOW.
该方法与业务方代码(调用业务的@Transactional方法)同在一个事务中,只要本地事务提交成功,本方法也会提交成功*/
executeLocalTransaction(message,object){
try{
xxService.doTrans;//调用@Transactional方法,之心本地事务
state=LocalTransactionState.UNKNOW;
}catch(exception){
state=rollback_message;
}
returen state;
}
/** 当前方法通过检查本地事务数据库中,是否有记录,来告知rocketMQ是commit还是rollback
如果存在记录,commit;
如果不存在,需设置查询次数:超过指定次数,未查询到消息,rollback;如果指定次数内未查到,unknown;
rocketmq设置一定频率回查事务,此外查询次数设置为15次*/
checkLocalTransaction{
//略…………………………
}
}
consumer端:
3.1 RocketMQ对事务消息的支持
其实根据上个小结的开发逻辑,可以知道,RocketMQ支持事务型消息,它的事务功能的实现,借助两阶段提交和定时事务状态回查决定commit/rollback。RocketMQ的事务消息实现原理如下:
1 应用程序在事务内完成相关业务操作后,调用RocketMQ的事务消息发送接口,发送prepare的half事务消息;
2 rocketMQ的server在收到类型prepare的消息,会首先备份消息的topic和consumerQueue,然后将消息存储在topic为RMQ_SYS_TRANS_HALF_TOPIC的消息消费队列中;
half发送成功后,MQServer回调producer的transactionListener监听器,executeLocalTransaction记录本地事务信息持久化(注意:当前方法,和本地业务操作同属一个事务,来确保消息发送与本地事务的原子性);
4 rocketMQ的server长时间没有收到producer端事务执行状态(或者只收到unknown)时,会开启定时任务,消费RMQ_SYS_TRANS_HALF_TOPIC主题消息,向producer端发起事务状态回查的请求;
5 producer端收到请求后,执行checkLocalTransaction查询本地事务消息表,决定事务状态:
case1:如果查到数据,commit提交;
case2:如果查不到:记录查询次数,如果未超过次数,返回unknown;如果超过次数,返回rollback。
rocketMQ允许设置回查间隔与回查次数,默认15次。
3.2 RocketMQ事务消息的源码分析
3.2.1 事务消息发送流程
1 RocketMQ事务消息相关类
1.1 TransactionMQProducer事务消息生产者对象
public class TransactionMQProducer extends DefaultMQProducer {
private int checkThreadPoolMinSize = 1;
private int checkThreadPoolMaxSize = 1;
private int checkRequestHoldMax = 2000;
//事务状态回查的异步执行线程池
private ExecutorService executorService;
//事务监听器,主要完成本地事务信息持久化、事务状态回查
private TransactionListener transactionListener;
@Override
public void start() throws MQClientException {
this.defaultMQProducerImpl.initTransactionEnv();
super.start();
}
//事务消息发送
@Override
public TransactionSendResult sendMessageInTransaction(final Message msg,
final Object arg) throws MQClientException {
if (null == this.transactionListener) {
throw new MQClientException("TransactionListener is null", null);
}
msg.setTopic(NamespaceUtil.wrapNamespace(this.getNamespace(), msg.getTopic()));
//调用defaultMQProducerImpl的事务消息发送方法
return this.defaultMQProducerImpl.sendMessageInTransaction(msg, null, arg);
}
1.2 TransactionListener事务监听器
public interface TransactionListener {
/**
* When send transactional prepare(half) message succeed, this method will be invoked to execute local transaction.
*
* @param msg Half(prepare) message
* @param arg Custom business parameter
* @return Transaction state
*/
LocalTransactionState executeLocalTransaction(final Message msg, final Object arg);
/**
* When no response to prepare(half) message. broker will send check message to check the transaction status, and this
* method will be invoked to get local transaction status.
*
* @param msg Check message
* @return Transaction state
*/
LocalTransactionState checkLocalTransaction(final MessageExt msg);
}
2 源码流程
首先,也业务模块中调用发送half事务消息,
………………producer端发送……………
TAG1 TransactionMQProducer.sendMessageInTransaction
public class TransactionMQProducer extends DefaultMQProducer {
@Override
public TransactionSendResult sendMessageInTransaction(final Message msg,
final Object arg) throws MQClientException {
if (null == this.transactionListener) {
throw new MQClientException("TransactionListener is null", null);
}
//设置msg的top信息
msg.setTopic(NamespaceUtil.wrapNamespace(this.getNamespace(), msg.getTopic()));
//调用DefaultMQProducerImpl的方法
return this.defaultMQProducerImpl.sendMessageInTransaction(msg, null, arg);
}
defaultMQProducerImpl是DefaultMQProducer内的属性,响应的方法,统统交给impl实现
DefaultMQProducerImpl
public TransactionSendResult sendMessageInTransaction(final Message msg,
final LocalTransactionExecuter localTransactionExecuter, final Object arg)
throws MQClientException {
//this.defaultMQProducer,如果是TransactionMQProducer,则从中中获取监听器
TransactionListener transactionListener = getCheckListener();
if (null == localTransactionExecuter && null == transactionListener) {
throw new MQClientException("tranExecutor is null", null);
}
// 忽略配置的 DelayTimeLevel 延迟时间级别的参数
if (msg.getDelayTimeLevel() != 0) {
MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_DELAY_TIME_LEVEL);
}
Validators.checkMessage(msg, this.defaultMQProducer);
SendResult sendResult = null;
/**…………………………………………………………………………………………为消息添加属性……………………………………………………………………………………………………*/
//STEP1 为消息添加prepared、producer-group属性。设置producerGroup目的是,在查询local事务状态时,可以从group中随机选择一个producer即可
//设置参数prepared为true
MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true");
//设置消息所在的生产者组
MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup());
try {
//TAG2 this.send(msg)
//STEP2 同步调用,发送消息到rocketMQ
sendResult = this.send(msg);
} catch (Exception e) {
throw new MQClientException("send message Exception", e);
}
/** …………………………………………………………………………根据sendResult的发送状态,确定本地事务的状态………………………………………………………………*/
LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;
Throwable localException = null;
switch (sendResult.getSendStatus()) {
case SEND_OK: {
try {
//为消息添加事务id的属性
if (sendResult.getTransactionId() != null) {
msg.putUserProperty("__transactionId__", sendResult.getTransactionId());
}
String transactionId = msg.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX);
if (null != transactionId && !"".equals(transactionId)) {
msg.setTransactionId(transactionId);
}
//传入为null,不执行
if (null != localTransactionExecuter) {
localTransactionState = localTransactionExecuter.executeLocalTransactionBranch(msg, arg);
} else if (transactionListener != null) {
log.debug("Used new transaction API");
//step3 执行本地事务executeLocalTransaction方法
localTransactionState = transactionListener.executeLocalTransaction(msg, arg);
}
if (null == localTransactionState) {
localTransactionState = LocalTransactionState.UNKNOW;
}
if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE) {
log.info("executeLocalTransactionBranch return {}", localTransactionState);
log.info(msg.toString());
}
} catch (Throwable e) {
log.info("executeLocalTransactionBranch exception", e);
log.info(msg.toString());
localException = e;
}
}
break;
case FLUSH_DISK_TIMEOUT:
case FLUSH_SLAVE_TIMEOUT:
case SLAVE_NOT_AVAILABLE:
localTransactionState = LocalTransactionState.ROLLBACK_MESSAGE;
break;
default:
break;
}
//step4 结束事务
try {
this.endTransaction(sendResult, localTransactionState, localException);
} catch (Exception e) {
log.warn("local transaction execute " + localTransactionState + ", but end broker transaction failed", e);
}
//step5 构造事务消息发送的方法返回result
TransactionSendResult transactionSendResult = new TransactionSendResult();
transactionSendResult.setSendStatus(sendResult.getSendStatus());
transactionSendResult.setMessageQueue(sendResult.getMessageQueue());
transactionSendResult.setMsgId(sendResult.getMsgId());
transactionSendResult.setQueueOffset(sendResult.getQueueOffset());
transactionSendResult.setTransactionId(sendResult.getTransactionId());
transactionSendResult.setLocalTransactionState(localTransactionState);
return transactionSendResult;
}
事务消息的发送过程,主要有如下步骤:
STEP1 为消息添加prepared、producer-group属性。设置producerGroup目的是,在查询local事务状态时,可以从group中随机选择一个producer即可;
STEP2 调用同步发送,发送消息到rocketMQ;
STEP3 根据sendResult的发送状态,确定本地事务的状态
CASE1 OK当发送结果成功时,执行本地事务executeLocalTransaction方法,来设置事务执行状态;
CASE2 如果消息刷新超时,slave不可用,标记事务状态为rollback;
CASE3 其他情况,事务状态仍旧是unknown
STEP4 结束事务 this.endTransaction();
STEP5 构造事务消息发送的方法返回result;
在事务消息发送过程中,保证事务一致性的操作,比较关键的步骤是,对事务状态LocalTransactionState的设置:
1 在prepared消息发送成功时,执行本地事务方法,确定自己状态;(也会有commit、rollback、unknown)
如果prepared发送,出现刷新超时和slave不可用,会rollback状态;
3 其他情况的发送失败,会标记事务状态为unknown;
TAG2 this.send(msg) 事务消息发送
具体的发送流程,和普通消息相同,只是对于prepared消息,有如下差别:
DefaultMQProducerImpl
private SendResult sendKernelImpl(final Message msg,){
final String tranMsg = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED);
if (tranMsg != null && Boolean.parseBoolean(tranMsg)) {
sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE;
}
}
在消息发送前,为消息的flag添加prepared的标志位。
………………broker端处理………………
broker端接收到producer的请求,对应的处理逻辑由BrokerController中注册的processor方法实现。
此处,对于sendMessage的请求,由sendProcessor处理。
TAG3 SendMessageProcessor.request--->sendMessage
public class SendMessageProcessor extends AbstractSendMessageProcessor implements NettyRequestProcessor {
private List<ConsumeMessageHook> consumeMessageHookList;
private RemotingCommand sendMessage(final ChannelHandlerContext ctx,
final RemotingCommand request,
final SendMessageContext sendMessageContext,
final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class);
final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader)response.readCustomHeader();
response.setOpaque(request.getOpaque());
response.addExtField(MessageConst.PROPERTY_MSG_REGION, this.brokerController.getBrokerConfig().getRegionId());
response.addExtField(MessageConst.PROPERTY_TRACE_SWITCH, String.valueOf(this.brokerController.getBrokerConfig().isTraceOn()));
log.debug("receive SendMessage request command, {}", request);
final long startTimstamp = this.brokerController.getBrokerConfig().getStartAcceptSendRequestTimeStamp();
if (this.brokerController.getMessageStore().now() < startTimstamp) {
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark(String.format("broker unable to service, until %s", UtilAll.timeMillisToHumanString2(startTimstamp)));
return response;
}
response.setCode(-1);
super.msgCheck(ctx, requestHeader, response);
if (response.getCode() != -1) {
return response;
}
final byte[] body = request.getBody();
int queueIdInt = requestHeader.getQueueId();
TopicConfig topicConfig = this.brokerController.getTopicConfigManager().selectTopicConfig(requestHeader.getTopic());
if (queueIdInt < 0) {
queueIdInt = Math.abs(this.random.nextInt() % 99999999) % topicConfig.getWriteQueueNums();
}
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(requestHeader.getTopic());
msgInner.setQueueId(queueIdInt);
if (!handleRetryAndDLQ(requestHeader, response, request, msgInner, topicConfig)) {
return response;
}
msgInner.setBody(body);
msgInner.setFlag(requestHeader.getFlag());
MessageAccessor.setProperties(msgInner, MessageDecoder.string2messageProperties(requestHeader.getProperties()));
msgInner.setPropertiesString(requestHeader.getProperties());
msgInner.setBornTimestamp(requestHeader.getBornTimestamp());
msgInner.setBornHost(ctx.channel().remoteAddress());
msgInner.setStoreHost(this.getStoreHost());
msgInner.setReconsumeTimes(requestHeader.getReconsumeTimes() == null ? 0 : requestHeader.getReconsumeTimes());
PutMessageResult putMessageResult = null;
//从message中获取属性集合
Map<String, String> oriProps = MessageDecoder.string2messageProperties(requestHeader.getProperties());
//获取消息是否是事务性prepared消息
String traFlag = oriProps.get(MessageConst.PROPERTY_TRANSACTION_PREPARED);
if (traFlag != null && Boolean.parseBoolean(traFlag)) {
if (this.brokerController.getBrokerConfig().isRejectTransactionMessage()) {
response.setCode(ResponseCode.NO_PERMISSION);
response.setRemark(
"the broker[" + this.brokerController.getBrokerConfig().getBrokerIP1()
+ "] sending transaction message is forbidden");
return response;
}
//TAG3.1 brokerController.getTransactionalMessageService().prepareMessage(msgInner)
//如果是事务性prepared消息,调用
putMessageResult = this.brokerController.getTransactionalMessageService().prepareMessage(msgInner);
} else {
//普通消息,执行普通的消息存储
putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner);
}
return handlePutMessageResult(putMessageResult, response, request, msgInner, responseHeader, sendMessageContext, ctx, queueIdInt);
}
TAG3.1 brokerController.getTransactionalMessageService().prepareMessage(msgInner)
TransactionalMessageServiceImpl
@Override
public PutMessageResult prepareMessage(MessageExtBrokerInner messageInner) {
//存储half消息
return transactionalMessageBridge.putHalfMessage(messageInner);
}
TransactionalMessageBridge
public PutMessageResult putHalfMessage(MessageExtBrokerInner messageInner) {
return store.putMessage(parseHalfMessageInner(messageInner));
}
//解析half消息
private MessageExtBrokerInner parseHalfMessageInner(MessageExtBrokerInner msgInner) {
MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_REAL_TOPIC, msgInner.getTopic());
MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_REAL_QUEUE_ID,
String.valueOf(msgInner.getQueueId()));
msgInner.setSysFlag(
MessageSysFlag.resetTransactionValue(msgInner.getSysFlag(), MessageSysFlag.TRANSACTION_NOT_TYPE));
//变更消息主题为RMQ_SYS_TRANS_HALF_TOPIC
msgInner.setTopic(TransactionalMessageUtil.buildHalfTopic());
msgInner.setQueueId(0);
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
return msgInner;
}
这里,是备份消息原来的topic、queueId到消息的属性中,然后将主题重新设置为RMQ_SYS_TRANS_HALF_TOPIC,消费队列变更为0.
然后 store.putMessage(parseHalfMessageInner(messageInner)),将消息存储在commitlog中,进而转发到RMQ_SYS_TRANS_HALF_TOPIC对应的消息消费队列。
从上述过程来看,消息未提交之前不会存入原来的主题,也就不能被消费。然后rocketMQ采用定人的单独线程任务,去消费该主题消息,然后再满足特定条件下,恢复消息主题,使得该事务消息被消费。
总结上述的事务发送流程,如下:
3.2.2 提交或回滚事务endTransaction
在事务消息发送过程的步骤,可知:
STEP1 为消息添加prepared、producer-group属性。设置producerGroup目的是,在查询local事务状态时,可以从group中随机选择一个producer即可;
STEP2 调用同步发送,发送消息到rocketMQ;
STEP3 根据sendResult的发送状态,确定本地事务的状态
CASE1 OK当发送结果成功时,执行本地事务executeLocalTransaction方法,来设置事务执行状态;
CASE2 如果消息刷新超时,slave不可以,标记事务状态为rollback;
CASE3 其他情况,事务状态仍旧是unknown
STEP4 结束事务 this.endTransaction();
STEP5 构造事务消息发送的方法返回result;
………………producer端发送endTrans………………
TAG4 endTransaction终结事务
可知,在执行STEP4 endTransaction时,业务事务还没有提交,所以在使用transactionListener.executeLocalTransaction方法记录事务消息状态后,应该返回unknown。而事务消息的commit或者rollback,应该根据消息状态的回查,再确定是否提交。
DefaultMQProducerImpl
public void endTransaction(
final SendResult sendResult,
final LocalTransactionState localTransactionState,
final Throwable localException) throws RemotingException, MQBrokerException, InterruptedException, UnknownHostException {
final MessageId id;
if (sendResult.getOffsetMsgId() != null) {
id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId());
} else {
id = MessageDecoder.decodeMessageId(sendResult.getMsgId());
}
String transactionId = sendResult.getTransactionId();
//根据所属的消息队列,获取broker地址信息
final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName());
//构造EndTransactionRequestHeader的请求
EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader();
requestHeader.setTransactionId(transactionId);
requestHeader.setCommitLogOffset(id.getOffset());
//根据本地事务状态,设置发送endTransaction的命令是commit、rollback还是not(不作为)
switch (localTransactionState) {
case COMMIT_MESSAGE:
requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE);
break;
case ROLLBACK_MESSAGE:
requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE);
break;
case UNKNOW:
requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE);
break;
default:
break;
}
requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup());
requestHeader.setTranStateTableOffset(sendResult.getQueueOffset());
requestHeader.setMsgId(sendResult.getMsgId());
String remark = localException != null ? ("executeLocalTransactionBranch exception: " + localException.toString()) : null;
//producer发送终结事务的信息
this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark,
this.defaultMQProducer.getSendMsgTimeout());
}
………………broker端处理endTrans………………
broker端处理终结事务的处理器为EndTransactionProcessor
TAG5 EndTransactionProcessor.processRequest处理终结事务请求
EndTransactionProcessor
@Override
public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws
RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
final EndTransactionRequestHeader requestHeader =
(EndTransactionRequestHeader)request.decodeCommandCustomHeader(EndTransactionRequestHeader.class);
LOGGER.info("Transaction request:{}", requestHeader);
if (BrokerRole.SLAVE == brokerController.getMessageStoreConfig().getBrokerRole()) {
response.setCode(ResponseCode.SLAVE_NOT_AVAILABLE);
LOGGER.warn("Message store is slave mode, so end transaction is forbidden. ");
return response;
}
if (requestHeader.getFromTransactionCheck()) {
switch (requestHeader.getCommitOrRollback()) {
//not
case MessageSysFlag.TRANSACTION_NOT_TYPE: {
LOGGER.warn("Check producer[{}] transaction state, but it's pending status."
+ "RequestHeader: {} Remark: {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
requestHeader.toString(),
request.getRemark());
return null;
}
case MessageSysFlag.TRANSACTION_COMMIT_TYPE: {
LOGGER.warn("Check producer[{}] transaction state, the producer commit the message."
+ "RequestHeader: {} Remark: {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
requestHeader.toString(),
request.getRemark());
break;
}
case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE: {
LOGGER.warn("Check producer[{}] transaction state, the producer rollback the message."
+ "RequestHeader: {} Remark: {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
requestHeader.toString(),
request.getRemark());
break;
}
default:
return null;
}
} else {
switch (requestHeader.getCommitOrRollback()) {
case MessageSysFlag.TRANSACTION_NOT_TYPE: {
LOGGER.warn("The producer[{}] end transaction in sending message, and it's pending status."
+ "RequestHeader: {} Remark: {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
requestHeader.toString(),
request.getRemark());
return null;
}
case MessageSysFlag.TRANSACTION_COMMIT_TYPE: {
break;
}
case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE: {
LOGGER.warn("The producer[{}] end transaction in sending message, rollback the message."
+ "RequestHeader: {} Remark: {}",
RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
requestHeader.toString(),
request.getRemark());
break;
}
default:
return null;
}
}
OperationResult result = new OperationResult();
//事务信息为commit的情况
if (MessageSysFlag.TRANSACTION_COMMIT_TYPE == requestHeader.getCommitOrRollback()) {
//执行提交事务的逻辑(获取消息的物理偏移量)
result = this.brokerController.getTransactionalMessageService().commitMessage(requestHeader);
if (result.getResponseCode() == ResponseCode.SUCCESS) {
RemotingCommand res = checkPrepareMessage(result.getPrepareMessage(), requestHeader);
if (res.getCode() == ResponseCode.SUCCESS) {
//构建新的消息对象,并恢复消息的topic、消费队列
MessageExtBrokerInner msgInner = endMessageTransaction(result.getPrepareMessage());
msgInner.setSysFlag(MessageSysFlag.resetTransactionValue(msgInner.getSysFlag(), requestHeader.getCommitOrRollback()));
msgInner.setQueueOffset(requestHeader.getTranStateTableOffset());
msgInner.setPreparedTransactionOffset(requestHeader.getCommitLogOffset());
msgInner.setStoreTimestamp(result.getPrepareMessage().getStoreTimestamp());
//然后再次发送消息,存储在commitlog中(此时消息主题为原来topic,会被转发到对应的消息消费队列,供消费者消费
RemotingCommand sendResult = sendFinalMessage(msgInner);
if (sendResult.getCode() == ResponseCode.SUCCESS) {
//如果重新存储成功,会删除prepared消息(此处不是真正删除,而是将prepared消息存储入RMQ_SYS_TRANS_OP_HALF_TOPIC,是为了未处理的事务进行回查时候,确定当前消息是否消费过的依据
this.brokerController.getTransactionalMessageService().deletePrepareMessage(result.getPrepareMessage());
}
return sendResult;
}
return res;
}
}
//事务信息为rollback的情况(不用恢复主题并重新发送到commitlog,直接删除----)
else if (MessageSysFlag.TRANSACTION_ROLLBACK_TYPE == requestHeader.getCommitOrRollback()) {
result = this.brokerController.getTransactionalMessageService().rollbackMessage(requestHeader);
if (result.getResponseCode() == ResponseCode.SUCCESS) {
RemotingCommand res = checkPrepareMessage(result.getPrepareMessage(), requestHeader);
if (res.getCode() == ResponseCode.SUCCESS) {
this.brokerController.getTransactionalMessageService().deletePrepareMessage(result.getPrepareMessage());
}
return res;
}
}
//事务信息为unknown的情况
response.setCode(result.getResponseCode());
response.setRemark(result.getResponseRemark());
return response;
}
上述,逻辑,如下:
case commit情况:
1 构建新的消息对象,并恢复消息的topic、消费队列
2 然后再次发送消息,存储在commitlog中(此时消息主题为原来topic,会被转发到对应的消息消费队列,供消费者消费
3 如果重新存储成功,会删除prepared消息(此处不是真正删除,而是将prepared消息存储入RMQ_SYS_TRANS_OP_HALF_TOPIC,是为了未处理的事务进行回查时候,确定当前消息是否消费过的依据
case rollback情况:
如果rollback的消息,省略恢复原主题并重新send存储到commitlog过程,直接删除在---也同样放入op队列中
case unknown情况:
不做任何处理