Rocketmq源码中关于分布式事物消息的实现并没有完全开源,本人是基于3.4.6分析。其中的类是TransactionMQProducer。
源码分析
- TransactionMQProducer是发送分布式事物消息的核心基础类,其中sendMessageInTransaction是主要发送方法。该方法的核心步骤主要有3步。
1.1. producer发送一条prepared消息至broker.
1.2. 调用LocalTransactionExecutor执行本地业务逻辑,提交事物。
1.3. 本地事物提交之后,发送事物确认消息。 - 分析一下sendMessageInTransaction源码
public TransactionSendResult sendMessageInTransaction(final Message msg,final LocalTransactionExecuter tranExecuter, final Object arg) throws MQClientException {
// 1. tranExecutor,需要应用自己开发实现
if (null == tranExecuter) {
throw new MQClientException("tranExecutor is null", null);
}
// 2. 检查消息各种属性和装填
Validators.checkMessage(msg, this.defaultMQProducer);
SendResult sendResult = null;
// 3.1 设置发送消息属性类型,事物预备消息
MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true");
// 3.2 设置消息所属的group
MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP,
this.defaultMQProducer.getProducerGroup());
try {
// 4. 发送预备消息
sendResult = this.send(msg);
}
catch (Exception e) {
throw new MQClientException("send message Exception", e);
}
// 5. 初始化本地事物装填--UNKNOW未知状态
LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;
Throwable localException = null;
// 6. 判断发送预备消息的状态
switch (sendResult.getSendStatus()) {
case SEND_OK: {
try {
if (sendResult.getTransactionId() != null) { msg.putUserProperty("__transactionId__",sendResult.getTransactionId());
}
// 7. 执行本地事物逻辑,用户自己实现的业务逻辑部分
localTransactionState = tranExecuter.executeLocalTransactionBranch(msg, arg);
if (null == localTransactionState) {
localTransactionState = LocalTransactionState.UNKNOW;
}
// 8.判断本地事物状态
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;
}
// 9 根据本地事物状态,发送事物确认消息。
try {
this.endTransaction(sendResult, localTransactionState, localException);
}
catch (Exception e) {
log.warn("local transaction execute " + localTransactionState
+ ", but end broker transaction failed", e);
}
// 1. 构建返回发送事物结果
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;
}
- 分析一下endTransaction源码
private void endTransaction(//
final SendResult sendResult, //
final LocalTransactionState localTransactionState, //
final Throwable localException) throws RemotingException, MQBrokerException,InterruptedException, UnknownHostException {
// 消息ID
final MessageId id = MessageDecoder.decodeMessageId(sendResult.getMsgId());
// 事物ID
String transactionId = sendResult.getTransactionId();
// 获取brokerAddr
final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName());
// 构建确认事物请求头信息
EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader();
// 设置事物请求ID
requestHeader.setTransactionId(transactionId);
// 设置消息的偏移量offset
requestHeader.setCommitLogOffset(id.getOffset());
// 判断本地事物状态
switch (localTransactionState) {
case COMMIT_MESSAGE:
/**设置成功消息类型**/ requestHeader.setCommitOrRollback(MessageSysFlag.TransactionCommitType);
break;
case ROLLBACK_MESSAGE:
/**设置回滚消息类型**/ requestHeader.setCommitOrRollback(MessageSysFlag.TransactionRollbackType);
break;
case UNKNOW:
requestHeader.setCommitOrRollback(MessageSysFlag.TransactionNotType);
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;
/**发送事物确认消息**/ this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark,
this.defaultMQProducer.getSendMsgTimeout());
}