Author: Heber

Introduction: There is such a general problem in the distributed system call scenario, that is, while executing a core business logic, it is also necessary to call multiple downstream businesses for business processing, and multiple downstream businesses and the current core business must be successful at the same time or at the same time. failure, thereby avoiding the inconsistency of partial success and failure. In short, the "transaction" in the message queue mainly solves the problem of data consistency between message producers and consumers. This article helps you better understand and use RocketMQ transaction messages by dismantling the usage scenarios, basic principles, implementation details and actual use of RocketMQ transaction messages.

Click the link below to view the video explanation:

https://yqh.aliyun.com/live/detail/29199

Scenario: Why do you need transactional messages

Taking the e-commerce transaction scenario as an example, the core operation of the user paying for the order will also involve changes in multiple subsystems such as downstream logistics delivery, point change, and shopping cart status clearing. The processing branches of the current business include:

  • Main branch order system status update: changed from unpaid to successful paid;
  • New logistics system status: add logistics records to be shipped, and create order logistics records;
  • Point system status change: change user points, update user points table;
  • Shopping cart system status change: clear the shopping cart and update the user's shopping cart record.

 title=

The characteristics of distributed system calls are: the execution of one core business logic requires calling multiple downstream businesses for processing at the same time. Therefore, how to ensure that the execution results of the core business and multiple downstream businesses are completely consistent is the main problem that needs to be solved for distributed transactions.

Traditional XA Transaction Scenario: Insufficient Performance

In order to ensure the consistency of the execution results of the above four branches, a typical solution is implemented by a distributed transaction system based on the XA protocol. The four call branches are encapsulated into a large transaction containing four independent transaction branches. The XA distributed transaction-based solution can satisfy the correctness of business processing results, but the biggest disadvantage is that the resource locking range is large and the concurrency is low in a multi-branch environment. , with the increase of downstream branches, the system performance will get worse and worse.

Based on common message scheme: Consistency guarantee is difficult

The above XA transaction-based solution is simplified, the order system changes are treated as local transactions, the remaining system changes are executed as the downstream of ordinary messages, and the transaction branch is simplified into ordinary messages + order table transactions, making full use of the ability to shorten messages asynchronously. link to improve concurrency.

 title=

In this scheme, the message downstream branch and the main branch of the order system change are prone to inconsistency, for example:

  • The message is sent successfully, but the order is not executed successfully, and the entire transaction needs to be rolled back;
  • The order is successfully executed, but the message is not sent successfully, and additional compensation is required to find the inconsistency;
  • The message sending timeout is unknown. At this time, it is impossible to determine whether to roll back the order or submit the order change.

Distributed transaction messages based on RocketMQ: support eventual consistency

In the above common message scheme, the essential reason why common messages and order transactions cannot be guaranteed to be consistent is that common messages cannot have the ability to commit, roll back and coordinate uniformly like a single-machine database transaction.

The distributed transaction message function based on the RocketMQ version of the message queue supports the two-phase submission capability on the basis of ordinary messages. Bind the two-phase commit to the local transaction to achieve the consistency of the global commit result.

 title=

The RocketMQ version of the message queue transaction message scheme has the advantages of high performance, scalability, and simple business development .

Fundamental

Concept introduction

  • Transaction messages : RocketMQ provides distributed transaction functions similar to XA or Open XA, and the eventual consistency of distributed transactions can be achieved through RocketMQ transaction messages;
  • Semi-transactional message : A message that cannot be delivered temporarily. The producer has successfully sent the message to the RocketMQ server, but the RocketMQ server has not received the second confirmation of the message from the producer. At this time, the message is marked as "temporarily unavailable." "Delivery" state, messages in this state are semi-transactional messages;
  • Message checkback: Due to network outages, producer application restarts, etc., the secondary confirmation of a transaction message is lost. When the RocketMQ server finds that a message has been a "semi-transactional message" for a long time through scanning, it needs to actively produce the message. The sender inquires about the final status (Commit or Rollback) of the message, and the inquiry process is the message back check.

transaction message life cycle

 title=

  • Initialization : The semi-transactional message is constructed and initialized by the producer and is to be sent to the server;
  • Transaction to be committed : Semi-transactional messages are sent to the server. Unlike ordinary messages, they will not be persisted directly by the server, but will be stored separately in the transaction storage system, waiting for the second-stage local transaction to return the execution result. Submit again. At this point the message is invisible to downstream consumers;
  • Message rollback : In the second stage, if the transaction execution result is clearly rollback, the server will rollback the semi-transaction message, and the transaction message process will be terminated;
  • Commit for consumption : In the second stage, if the transaction execution result is clearly committed, the server will re-store the semi-transaction message to the ordinary storage system. At this time, the message is visible to downstream consumers, waiting to be acquired and consumed by the consumer;
  • Consuming: The process in which the message is acquired by the consumer and processed according to the consumer's local business logic. At this time, the server will wait for the consumer to complete the consumption and submit the consumption result. If no response is received from the consumer after a certain period of time, RocketMQ will retry the message. For details, see Message Retry;
  • Consumption submission : The consumer completes the consumption process and submits the consumption result to the server. The server marks that the current message has been processed (including consumption success and failure); RocketMQ supports retaining all messages by default, and the message data will not be deleted immediately. , just the logical marker has been consumed. Before the message is deleted when the storage time expires or the storage space is insufficient, consumers can still go back and re-consume the message.
  • Message deletion : When the message storage period expires or the storage space is insufficient, RocketMQ will clean up the oldest saved message data according to the rolling mechanism, and delete the message from the physical file.

Basic process of transaction message

The transaction message interaction process is shown in the following figure:

 title=

  1. The producer sends the message to the RocketMQ server;
  2. After the RocketMQ server successfully persists the message, it returns Ack to the producer to confirm that the message has been sent successfully. At this time, the message is marked as "cannot be delivered temporarily", and the message in this state is a semi-transactional message;
  3. The producer starts executing local transaction logic;
  4. The producer submits the secondary confirmation result (Commit or Rollback) to the server according to the execution result of the local transaction, and the processing logic after the server receives the confirmation result is as follows:
    • The secondary confirmation result is Commit: the server marks the semi-transactional message as deliverable and delivers it to the consumer;
    • The secondary confirmation result is Rollback: the server will roll back the transaction and will not deliver the semi-transaction message to the consumer.
  1. In the special case of disconnection or restart of the producer application, if the server does not receive the secondary confirmation result submitted by the sender, or the secondary confirmation result received by the server is Unknown, after a fixed period of time, the service The end will initiate a message check back on the message producer, that is, any producer instance in the producer cluster;
  2. After the producer receives the message review, it needs to check the final result of the local transaction execution corresponding to the message;
  3. The producer submits the secondary confirmation again according to the final state of the local transaction checked, and the server still processes the semi-transaction message according to step 4.

Implementation details: How RocketMQ transaction messages are implemented

 title=

According to the needs of the basic process of sending transaction messages, the implementation is divided into three main processes: receiving and processing Half messages, processing Commit or Rollback commands, and checking transaction messages.

Handling Half messages

After the sender sends the Half message to the Broker in the first stage, the Broker processes the Half message. The broker process refers to the following figure:

 title=

The specific process is to first convert the message topic to RMQ_SYS_TRANS_HALF_TOPIC, and write the rest of the message content to the Half queue. For specific implementation, refer to the logical processing of SendMessageProcessor.

Commit or Rollback command processing

After the sender completes the local transaction, it continues to send Commit or Rollback to the Broker. Since the current transaction has been completed, the Broker needs to delete the original Half message. Due to the appendOnly feature of RocketMQ, the Broker implements the mark deletion through the OP message. The broker process refers to the following figure:

 title=

  • Commit . The Broker writes the OP message, the body of the OP message specifies the queueOffset of the Commit message, and the Half message has been deleted before marking; at the same time, the Broker reads the original Half message, restores the Topic, and rewrites it to the CommitLog, and consumers can pull the consumption;
  • Rollback . Broker also writes OP messages, and the process is the same as Commit. But the Half message will not be read and restored subsequently. In this way, the consumer will not consume the message.

The specific implementation is in EndTransactionProcessor.

transaction message check

If the sender executes the process at transaction time, sends the UNKNOWN command, or the broker/sender restarts the publication, etc., the OP message marked for deletion in process 2 may be missing. Therefore, a transaction message check process is added, which is executed periodically by asynchronous threads. (transactionCheckInterval defaults to 30s interval), check status for these Half messages missing OP messages. Refer to the following figure for details:

 title=

The transaction message check process scans the current OP message queue and reads the queueOffset of the Half message that has been marked for deletion. If it is found that a Half message does not have the corresponding mark of the OP message and has timed out (transactionTimeOut defaults to 6 seconds), read the Half message and rewrite it to the half queue, and send the check command to the original sender to check the transaction status; if there is no timeout, It will wait and read the OP message queue to obtain new OP messages.

In addition, in order to avoid the long-term inability to determine the transaction status due to the exception of the sender, if the bornTime of a Half message exceeds the maximum retention time (transactionCheckMaxTimeInMs defaults to 12 hours), the message will be automatically skipped and no longer checked.

Specific implementation reference:

TransactionalMessageServiceImpl#check method.

In Action: Using Transactional Messages

After understanding the principle of RocketMQ transaction messages, let's see how to use transactions. First, we need to create a topic of type "transaction message", which can be created using console or CLi commands.

 title=

Compared with ordinary messages, transaction messages need to modify the following points:

  • Before sending a transaction message, you need to open the transaction and associate the local transaction execution.
  • To ensure transaction consistency, a transaction checker and a list of topics to send pre-bound transaction messages must be set when building a producer. The built-in transaction checker on the client side will perform abnormal state recovery on bound transaction topics.

 title=

When the transaction message is committed, the message is actually a normal message delivered to the user's topic. So for consumers, it is no different from the consumption of ordinary messages.

 title=

Notice:

  1. Avoid timeouts caused by a large number of pending transactions: initiate transaction checkbacks in the event of an exception in the transaction commit phase to ensure transaction consistency; but producers should try to avoid local transactions returning unknown results; a large number of transaction checks will lead to system performance damage, and it is easy to cause transaction processing delays;
  2. The Group ID of the transaction message cannot be shared with the Group ID of other types of messages: unlike other types of messages, the transaction message has a checkback mechanism, and the server will query the producer client according to the Group ID during the checkback;
  3. Transaction timeout mechanism: After a semi-transactional message is sent to the server by the producer, if the server cannot confirm the commit or rollback status within the specified time, the message will be rolled back by default.

Today, through the introduction of RocketMQ transaction message, I hope to help you have a deeper understanding of the principle and application of transaction message, and also hope that RocketMQ transaction message can help you solve business problems more effectively. If you are interested in RocktMQ business news, you are also welcome to scan the QR code below to join the DingTalk group to communicate~

 title=

Click here to enter the official website for more details~


阿里云云原生
1k 声望302 粉丝