RocketMQ事务消息源码分析

177 阅读4分钟

Apache RocketMQ 是一款分布式消息中间件,支持多种消息模式,其中包括事务消息。事务消息为分布式事务场景提供了强有力的支持。本文将详细分析 RocketMQ 的事务消息实现原理及其源码。

什么是事务消息?

事务消息是指一组消息的发送与某个本地事务操作需要保证一致性。如果本地事务操作成功,消息将被发送;如果本地事务操作失败,消息将回滚。这种机制在分布式系统中非常有用,尤其是需要保证数据一致性的时候。

RocketMQ 的事务消息机制可以理解为两阶段提交的实现:

  1. 预提交消息(Prepare Message): 在本地事务执行之前,首先发送一条半消息(Half Message)。
  2. 本地事务执行并确认: 本地事务执行成功后,再确认提交这条消息(Commit);如果本地事务失败,则回滚这条消息(Rollback)。
  3. 事务状态回查: 如果在提交阶段未收到事务确认消息,Broker 会主动回查 Producer 以获取事务状态。

RocketMQ 事务消息的架构

事务消息的实现涉及三个主要角色:

  • Producer: 负责发送事务消息。
  • Broker: 保存半消息并管理事务状态。
  • Consumer: 消费成功提交的事务消息。

事务消息的核心流程包括以下几个步骤:

  1. Producer 发送事务消息(Prepare Message)。
  2. Broker 存储半消息并响应 Producer。
  3. Producer 执行本地事务逻辑。
  4. Producer 根据本地事务的执行结果提交(Commit)或回滚(Rollback)事务消息。
  5. 如果 Broker 未收到 Producer 的事务确认消息,则会主动回查 Producer。

接下来,我们将从源码角度深入分析各个步骤。


源码分析

RocketMQ 的事务消息主要涉及以下几个模块:

  • TransactionMQProducer
  • TransactionListener
  • TransactionalMessageService
  • TransactionalMessageCheckService
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 负责处理事务消息的存储和状态变更,主要涉及以下逻辑:

  1. 存储半消息: 当 Producer 发送半消息时,Broker 会将其存储到一个特殊的队列中。
  2. 提交或回滚消息: 根据 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 的事务消息基于两阶段提交协议,核心流程分为预提交、本地事务执行和确认提交。其源码设计中通过 TransactionMQProducerTransactionListenerTransactionalMessageService 模块协同工作,确保了事务消息的可靠性。

事务消息适用于以下场景:

  • 分布式系统中的跨服务一致性问题。
  • 需要高可靠消息传递且伴随事务逻辑的场景。

通过对 RocketMQ 事务消息的深入了解,开发者可以更加灵活地应用这一特性,解决分布式系统中的一致性问题。