Backend Development 6 min read

Implementation Principles of Distributed Transaction Messages in RocketMQ

This article explains how RocketMQ implements distributed transaction messages using a two‑phase commit model, detailing the problems with RPC and ordinary MQ, the step‑by‑step workflow, relevant code snippets, and how consistency is ensured across microservice subsystems.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
Implementation Principles of Distributed Transaction Messages in RocketMQ

In an e‑commerce order‑payment scenario, the core operation triggers changes in downstream subsystems such as logistics, points, and shopping‑cart status; using RPC communication can lengthen the process and require distributed transactions, leading to performance issues.

Ordinary MQ messages cannot guarantee atomicity with the local transaction, causing problems like successful message send with local transaction failure, or network timeouts leaving the order system unaware of the message state.

RocketMQ addresses these issues by providing distributed transaction messages that support a two‑phase commit, binding the local transaction with the message to achieve global consistency.

1. Producer sends a half‑transaction message. The producer must implement a TransactionListener and set the message’s transaction properties, for example:

MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true");
MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup());

The constant is defined as:

public static final String PROPERTY_TRANSACTION_PREPARED = "TRAN_MSG";

2. Broker receives the half‑transaction message. It stores the message, marks its topic as RMQ_SYS_TRANS_HALF_TOPIC (defined as "RMQ_SYS_TRANS_HALF_TOPIC" ) and places it in a single internal queue that is invisible to consumers.

RMQ_SYS_TRANS_HALF_TOPIC = "RMQ_SYS_TRANS_HALF_TOPIC";

3. After successful storage, the broker may still encounter a send failure. The producer decides whether to commit or roll back based on the outcome of its local transaction.

4. Producer issues a Commit or Rollback request. The broker either deletes the half‑transaction message or restores it to the original topic and queue, making it visible to consumers.

5. If the commit/rollback request times out, the broker periodically checks the transaction status. The check is performed by the service org.apache.rocketmq.broker.transaction.queue.TransactionalMessageServiceImpl#check , using configuration values such as:

long timeout = brokerController.getBrokerConfig().getTransactionTimeOut();
int checkMax = brokerController.getBrokerConfig().getTransactionCheckMax();

The default maximum number of checks is:

private int transactionCheckMax = 15;

6. When the maximum number of checks is exceeded, the half‑transaction message is moved to the TRANS_CHECK_MAXTIME_TOPIC queue for manual monitoring and intervention.

Overall, RocketMQ’s distributed transaction messages combine the two‑phase commit with local transaction logic, ensuring that the global commit result is consistent even if the broker encounters failures, and reducing the risk of duplicate messages or data inconsistency across microservices.

MicroservicesBackend developmentMessage Queuerocketmqdistributed transactionsTransactional Messaging
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.