ApsaraMQ for RocketMQ supports distributed transactional messages. Transactional messages apply to scenarios in which eventual consistency is required. This topic describes the concepts, benefits, scenarios, interaction process, usage notes, and sample code of ApsaraMQ for RocketMQ transactional messages.
Terms
Transactional message: ApsaraMQ for RocketMQ provides a distributed transaction processing feature similar to X/Open XA to ensure transaction consistency in ApsaraMQ for RocketMQ.
Half message: A half message is a message that temporarily cannot be delivered. If the producer sends a message to the ApsaraMQ for RocketMQ broker, but the broker does not receive the second acknowledgment (ACK) from the producer, the message is marked as "temporarily undeliverable". A message in this state is called a half message.ApsaraMQ for RocketMQ
Message status check: The second ACK for a transactional message may be lost if a transient connection occurs in the network or the producer application is restarted. When the ApsaraMQ for RocketMQ broker finds that a message remains as a half message for an extended period of time, the broker sends a request to the producer to check whether the final status of the message is Commit or Rollback.
Benefits
ApsaraMQ for RocketMQ uses distributed transactional messages to decouple applications and ensure the final consistency of data. Traditional large transactions can be divided into smaller transactions. This operation improves efficiency. The operation also ensures the availability of the core system when an exception occurs in an application. If an application remains unable to receive messages, you can supplement or correct the data only for the application without the need to roll back all messages.
Scenarios
When users add items to their shopping carts on e-commerce applications, the shopping cart system and the trading system are involved. Distributed transactional messages can be asynchronous processed. This operation ensures the eventual consistency between the two systems. In this scenario, the trading system is crucial, and the distributed transaction processing feature must make sure that orders are successfully placed. The shopping cart system can subscribe to only the topics related to orders from ApsaraMQ for RocketMQ and then execute corresponding transactions. This way, the distributed transaction processing feature can ensure the eventual consistency between the two systems.
Interaction process
The following figure shows the interaction process of transactional messages.
The procedure for sending a transactional message includes the following steps:
A producer sends a half message to the ApsaraMQ for RocketMQ broker.
The ApsaraMQ for RocketMQ broker converts the message into a persistent message, and sends an ACK to the producer to confirm that the message is received. In this case, the message is a half message.
The producer executes a local transaction.
The producer sends a second ACK to the broker to submit the execution result of the local transaction. The execution result may be Commit or Rollback.
If the status of the message received by the broker is Commit, the broker marks the half message as deliverable and delivers the message to the consumer.
If the status of the message received by the broker is Rollback, the broker rolls back the transaction and does not deliver the half message to the consumer.
The network is disconnected or the producer application is restarted. In this case, if the broker does not receive a second ACK or the status of the half message is Unknown, the broker waits a period of time and sends a request to a producer in the producer cluster to query the status of the half message.
The following steps provide the instructions for checking the status of a transactional message:
After the producer receives the request, the producer checks the execution result of the local transaction that corresponds to the half message.
The producer sends another ACK to the ApsaraMQ forRocketMQ broker based on the execution result of the local transaction. Then, the broker processes the half message by following Step 4.
Usage notes
Rules for sending messages
When a producer sends a message to the broker and executes the local transaction, one of the following states is returned in the
execute
method:TransactionStatus.CommitTransaction
: The transaction is committed. The consumer can consume the message.TransactionStatus.RollbackTransaction
: The transaction is rolled back. The message is discarded and cannot be consumed.TransactionStatus.Unknow
: The transaction is in an unknown state. After a period of time, the ApsaraMQ for RocketMQ broker sends a request to check the message status.
You must specify the implementation class of the
LocalTransactionChecker
method when you create a producer of transactional messages by callingONSFactory.createTransactionProducer
. This way, the broker can check the status of the transactional messages if exceptions occur.Rules for checking the message status: After the local transaction is executed, the ApsaraMQ for RocketMQ broker receives an ACK indicating that the execution result is
TransactionStatus.Unknow
, or the producer exits unexpectedly and does not submit the execution result of the local transaction. In this case, the ApsaraMQ for RocketMQ broker sends a request to the producer to check the execution result of the local transaction. If the broker fails to obtain the result, the broker sends the request at a specified interval.Check interval: By default, the broker sends a request every 30 seconds for 12 hours to check the status of a half message.
Wait time before checking the status of a newly received half message: This parameter is user-defined. When the broker needs to initiate the periodic message status check, but the wait time before the status of a newly received half message is checked does not elapse, the broker does not check the status of the message.
Java is used in the following example. The setting indicates that the wait time before the status of a newly received half message is checked is 60 seconds.
Message message = new Message(); message.putUserProperties(PropertyKeyConst.CheckImmunityTimeInSeconds,"60");
NoteHowever, the actual time before the status of the newly received message is checked is 0 to 30 seconds later than the expected time. This is because the broker checks the message status at a default interval.
For example, if you set the wait time before the status of a newly received message is checked to 60 seconds, but the broker initiates the periodic check at the 58th second after a new half message is received, the message is not checked. After 30 seconds, the broker initiates another periodic check at the 88th second after the new half message is received. In this case, the message is checked. The time when the message is checked is 28 seconds later than the expected time.
Rules for consuming messages
Transactional messages cannot share group IDs with messages of other types. The difference between transactional messages and messages of other types is that transactional messages provide the mechanism of message status check. The ApsaraMQ for RocketMQ broker can query the message producers by group ID.
Sample code
The sample code in different programming languages for sending and subscribing to transactional messages is provided in the following topics:
TCP
HTTP
Python SDK Send and receive transactional messages
Node.js SDK Send and receive transactional messages