The ultimate showdown of MQ players: comparing several mainstream MQ solutions to realize distributed transactions

1. MQ implements distributed transactions

In the implementation of distributed transactions, ACK messages and half-messages are two different mechanisms for implementing distributed transactions. What they have in common is that they both use the two-phase commit mechanism, but their implementation details and applicable scenarios are different. different. have some differences and characteristics. The following is a comparison of ACK messages and half messages in implementing distributed transactions:

ACK message (Acknowledgment):

  • The ACK message means that in a distributed transaction, the receiver (consumer) of the message sends an ACK (confirmation) to the sender (producer) of the message after successfully processing the message.
  • After the producer sends a message, it needs to wait for the consumer to send an ACK to confirm that the message has been processed correctly.
  • If the message does not receive ACK confirmation, the producer can choose to resend the message to ensure the reliability of the message.
  • The mechanism of the ACK message can ensure the reliability and consistency of the message, but it needs to rely on the availability and stability of the consumer.

When using ACK messages to implement distributed transactions, it is necessary to include the operation of sending messages in local transactions, and send ACK messages to confirm the sending of messages after the local transactions are committed. This method can ensure the atomicity of sending messages and local transactions, thereby achieving the consistency and reliability of distributed transactions.

Half-Message:

  • Semi-message is a mechanism for implementing distributed transactions through message queues, usually using the transaction function or message reliability mechanism of message queues.
  • In a half-message, the operation of a transaction is split into two steps: sending the half-message and confirming the half-message.
  • When sending a half message, the message is sent to the message queue but not consumed immediately. At this time, the message is in the pending confirmation state.
  • After executing the local transaction logic, if successful, sending a confirmation message, the message queue will officially mark the half-message as a consumable state, and finally be consumed by the consumer.
  • If the local transaction logic fails, you can choose not to send a confirmation message, so that the half message times out or is discarded, and the rollback operation of the transaction is realized.
  • The half-message mechanism can ensure the reliability and consistency of distributed transactions without relying on the availability of consumers.

When comparing the above two mechanisms, the key point is the guarantee of reliability and consistency. ACK messages achieve reliability through consumer ACK acknowledgments, but depend on the availability and stability of consumers. Half-message achieves reliability and consistency through the transaction or reliability mechanism of the message queue, and does not depend on the confirmation of the consumer. At the same time, the semi-message mechanism can also support the rollback operation of distributed transactions.

The choice of whether to use ACK messages or half messages depends on the requirements and characteristics of the application scenario. Factors such as message reliability, performance, consumer availability requirements, and transaction rollback requirements need to be considered comprehensively.

The ACK message method requires the application to process message sending and confirmation more actively, while the semi-message method is responsible for coordinating the transaction status by the message middleware

2. MQ middleware realizes the principle of distributed transactions

2.1、Rocketmq

The core idea of ​​RocketMQ to implement distributed transactions is to use the two-phase commit (Two-Phase Commit, referred to as 2PC) protocol to ensure transactional and consistency of messages.

Specifically, RocketMQ uses two concepts of semi-message and transaction listener to realize. The following are the core ideas and steps for RocketMQ to implement distributed transactions:

  1. Transaction message sent:
  • In a distributed transaction, the application sends the transaction messages that need to be sent to RocketMQ.
  • The sent message is in the Half-Message state, indicating that the transaction has not been committed.

2. Execute local transaction logic:

  • After the message is sent, the application performs local transactional logic related to the message, such as database operations or other operations.

3. Submit the transaction:

  • If the local transaction logic is successfully executed, the application sends a message confirmation request to RocketMQ.
  • After RocketMQ receives the confirmation request, it will mark the half message as submittable.

4. Check back to confirm:

  • After the transaction is committed, RocketMQ will perform a checkback confirmation (Check Confirm) mechanism to ensure the consistency of distributed transactions.
  • RocketMQ will send a checkback request to the application, asking the application to confirm the final status of the transaction.

5. Confirm the transaction:

  • After the application receives the checkback request, it confirms according to the state of the local transaction.
  • If the local transaction is executed successfully and the commit is confirmed, the application sends a confirmation request to RocketMQ to mark the half message as committed.
  • If the execution of the local transaction fails or the rollback is confirmed, the application sends a confirmation request to RocketMQ to mark half of the message as rolled back.

Through the above steps, RocketMQ realizes the core idea of ​​distributed transactions. It uses a two-phase commit protocol to interact in the message sending phase and the confirmation phase to ensure the reliability and consistency of transaction messages.

It should be noted that RocketMQ's distributed transactions also involve message review and transaction status management. If the application fails to receive the checkback request during the checkback confirmation phase, RocketMQ will automatically process it according to the preset timeout period and mark the unconfirmed message as rollback.

The core idea of ​​RocketMQ to implement distributed transactions is to use a two-phase commit protocol to ensure the consistency and reliability of transaction messages through steps such as message sending, local transaction execution, and confirmation checkback.

2.2、Rabbitmq

The core idea of ​​RabbitMQ to implement distributed transactions is based on message confirmation and dead letter queues to ensure reliable delivery and consumption of messages.

Specifically, RabbitMQ uses two mechanisms: producer confirmation and consumer confirmation . The following are the core ideas and steps for RabbitMQ to implement distributed transactions:

  1. Message sending phase:
  • In a distributed transaction, the application sends the message to be sent to the specified Exchange (switch) and Routing Key (routing key) through the RabbitMQ Channel (channel).
  • At this stage, messages are sent to RabbitMQ, but not consumed immediately.

2. Confirmation stage:

  • After the message sending phase, the application executes message-related local transaction logic, such as database operations or calls to other external systems.
  • If the local transaction logic is successfully executed, the application will send a confirmation message to RabbitMQ, indicating that the message can be formally processed.
  • If the local transaction logic fails, the application can choose not to send the confirmation message, make the message timeout or be discarded, and implement the rollback operation of the transaction.

RabbitMQ implements the idea of ​​distributed transactions by splitting transaction operations into two phases: sending messages and confirming messages. The advantage of this is that sending a message is a lightweight operation without waiting for the execution result of the local transaction, thereby improving the throughput and performance of the message.

It should be noted that in order to ensure the reliability and consistency of distributed transactions, applications need to handle abnormal conditions, such as local transaction logic failures, network failures, or application crashes. In these cases, applications should have mechanisms in place to handle unacknowledged messages to avoid data inconsistencies. The core idea of ​​RabbitMQ to implement distributed transactions is to split the transaction operation into two stages of message sending and confirmation, and realize the commit or rollback of the transaction by confirming the message, so as to ensure the data consistency of the distributed system.

2.3、Kafka

The following is a common approach, called "Kafka Transactions", that can be used to implement distributed transactions:

  1. Start a Kafka transaction: On the producer side, you can start a Kafka transaction by calling the initTransactions() method. This will associate a transaction ID with the current thread and put the producer in transactional mode.
  2. Start transaction: The producer can call the beginTransaction() method to start a new transaction. After this, all messages sent to the Kafka topic will be associated with this transaction.
  3. Send a message: In a transaction, send a message to a Kafka topic by calling the send() method. These messages are not committed to the topic immediately, but are cached on the producer side until the transaction commits.
  4. Perform other operations: In a transaction, you can perform other operations, such as querying the database, calling other services, etc.
  5. Commit the transaction: Once all the messages have been sent, you can call the commitTransaction() method to commit the transaction. This will submit all messages cached on the producer side to the Kafka topic together.
  6. Handle transaction rollback: If an error occurs during the transaction or the transaction needs to be rolled back, you can call the abortTransaction() method to abort the current transaction. This will clear the producer's cached messages from being committed to the Kafka topic.

It should be noted that the consumer side can also participate in distributed transactions to ensure transaction consistency in the process of consuming messages.

=============================

If the article is helpful to you, please don't forget to add attention and like it!

Guess you like

Origin blog.csdn.net/citywu123/article/details/131433039