Apache RocketMQ 是一款分布式消息中间件,支持多种消息模式,其中包括事务消息。事务消息为分布式事务场景提供了强有力的支持。本文将详细分析 RocketMQ 的事务消息实现原理及其源码。
什么是事务消息?
事务消息是指一组消息的发送与某个本地事务操作需要保证一致性。如果本地事务操作成功,消息将被发送;如果本地事务操作失败,消息将回滚。这种机制在分布式系统中非常有用,尤其是需要保证数据一致性的时候。
RocketMQ 的事务消息机制可以理解为两阶段提交的实现:
- 预提交消息(Prepare Message): 在本地事务执行之前,首先发送一条半消息(Half Message)。
- 本地事务执行并确认: 本地事务执行成功后,再确认提交这条消息(Commit);如果本地事务失败,则回滚这条消息(Rollback)。
- 事务状态回查: 如果在提交阶段未收到事务确认消息,Broker 会主动回查 Producer 以获取事务状态。
RocketMQ 事务消息的架构
事务消息的实现涉及三个主要角色:
- Producer: 负责发送事务消息。
- Broker: 保存半消息并管理事务状态。
- Consumer: 消费成功提交的事务消息。
事务消息的核心流程包括以下几个步骤:
- Producer 发送事务消息(Prepare Message)。
- Broker 存储半消息并响应 Producer。
- Producer 执行本地事务逻辑。
- Producer 根据本地事务的执行结果提交(Commit)或回滚(Rollback)事务消息。
- 如果 Broker 未收到 Producer 的事务确认消息,则会主动回查 Producer。
接下来,我们将从源码角度深入分析各个步骤。
源码分析
RocketMQ 的事务消息主要涉及以下几个模块:
TransactionMQProducerTransactionListenerTransactionalMessageServiceTransactionalMessageCheckService
1. TransactionMQProducer
TransactionMQProducer 是事务消息的核心入口类。我们通过它发送事务消息。
TransactionMQProducer producer = new TransactionMQProducer("transaction_group");
producer.setTransactionListener(new TransactionListenerImpl());
producer.start();
Message msg = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
SendResult result = producer.sendMessageInTransaction(msg, null);
sendMessageInTransaction 方法是发送事务消息的关键,代码简化如下:
public TransactionSendResult sendMessageInTransaction(final Message msg, final Object arg) {
// 1. 发送半消息
SendResult sendResult = this.defaultMQProducerImpl.send(msg);
// 2. 执行本地事务逻辑
LocalTransactionState localTransactionState = listener.executeLocalTransaction(msg, arg);
// 3. 根据本地事务状态,提交或回滚消息
this.endTransaction(sendResult, localTransactionState);
}
关键点:
- 半消息(Prepare Message)通过
defaultMQProducerImpl.send方法发送到 Broker。 - 本地事务逻辑由
TransactionListener实现的executeLocalTransaction方法完成。 - 根据本地事务的返回状态调用
endTransaction方法,通知 Broker 提交或回滚事务。
2. TransactionListener
TransactionListener 是事务监听器接口,定义了两个方法:
public interface TransactionListener {
LocalTransactionState executeLocalTransaction(final Message msg, final Object arg);
LocalTransactionState checkLocalTransaction(final MessageExt msg);
}
executeLocalTransaction: 执行本地事务。checkLocalTransaction: 当 Broker 无法获取事务状态时,回调此方法进行事务状态检查。
用户需要实现该接口以定义具体的事务逻辑。
3. TransactionalMessageService
TransactionalMessageService 负责处理事务消息的存储和状态变更,主要涉及以下逻辑:
- 存储半消息: 当 Producer 发送半消息时,Broker 会将其存储到一个特殊的队列中。
- 提交或回滚消息: 根据 Producer 的确认请求,将半消息从特殊队列转移到目标队列(提交)或丢弃(回滚)。
存储半消息的代码逻辑在 TransactionalMessageBridge 中:
public PutMessageResult putHalfMessage(MessageExtBrokerInner messageInner) {
return this.defaultMessageStore.putMessage(messageInner);
}
提交消息的核心代码在 TransactionalMessageService#commitMessage 方法中:
public boolean commitMessage(String prepareMessageId) {
MessageExt prepareMsg = getMessageById(prepareMessageId);
// 转移到目标队列
return putMessageToTargetQueue(prepareMsg);
}
4. TransactionalMessageCheckService
TransactionalMessageCheckService 是 Broker 的事务状态检查服务。当 Broker 未收到事务的提交或回滚确认消息时,会定期触发状态检查。
检查逻辑位于 TransactionalMessageCheckService#check 方法中:
public void check(long transactionTimeout, int transactionCheckMax) {
List<MessageExt> halfMessages = getHalfMessages();
for (MessageExt msg : halfMessages) {
// 触发 Producer 回查
producer.checkLocalTransaction(msg);
}
}
通过回查机制,确保事务消息的最终一致性。
总结
RocketMQ 的事务消息基于两阶段提交协议,核心流程分为预提交、本地事务执行和确认提交。其源码设计中通过 TransactionMQProducer、TransactionListener 和 TransactionalMessageService 模块协同工作,确保了事务消息的可靠性。
事务消息适用于以下场景:
- 分布式系统中的跨服务一致性问题。
- 需要高可靠消息传递且伴随事务逻辑的场景。
通过对 RocketMQ 事务消息的深入了解,开发者可以更加灵活地应用这一特性,解决分布式系统中的一致性问题。