Rocketmq: RocketMQ Feature Request: Transaction-Aware Message

Created on 23 Apr 2018  ·  6Comments  ·  Source: apache/rocketmq

Messaging is a major approach to decouple distributed systems. However, when trying to decouple system modules whose boundaries are associated with transactions, it is subtle to determine when to send messages. For example, when module A completes a database transaction, it needs to send a message to notify module B, C, and D to perform subsequent actions. The problem is what the best time point to send the message is in comparison with database transaction. If we sent the message before database transaction, what if the application or database server crashed out. The same counts if the transaction rolls back due to any potential reason. If we sent the message after the transaction commits, there will be chances that application server may suffer crashes before message delivery is made. Thus, to maintain consistency of the whole system, we need to either implement an extra module to periodically check messages of each transaction is sent given messages are designed to send after the transaction commits and supplementally send those missed ones to achieve eventual consistency or make our messaging system transaction aware.

The first option is viable, but it excessively complicates business application systems and brings about noticeable overhead as the extra module has to repeatedly check committed transactions and messages sent are in accordance after a period of time. The latter choice, however, confines complexities to the messaging system itself and once achieved, all application developers may enjoy simplicity and consistency.

To achieve the goal described above, we define a new type of message: transaction aware message. A transaction-aware message is composed of a pair of deliverable messages: prepare-message and commit/rollback message. Prepare messages are supposed to be sent before local transaction commits/roll-back, which are not visible to consumers. Commit/rollback messages are sent after transaction commits/rolls back. Brokers are responsible to inquire application servers, which share the same role with those prepare-message senders, to handle pending prepare messages after the defined period of time. On receiving of the commit message, the transaction aware message is made visible to consumers; Similarly, on receiving of rollback message, pending status of the corresponding prepare message is canceled quietly and consumers are completely unaware in the whole process.

enhancement new feature

Most helpful comment

Thanks for @lizhanhui's feature request,and as mentioned above, with the rise of micro service architecture,developers are eager to use a mechanism to ensure the eventual consistency of transaction, especially in distributed systems, and we also found transaction aware message can achieve this goal gracefully, so we intend to implement this feature in rocketMQ, and this process is as follows:

transaction

In our design, we will define a pair of message: named half message and commit/rollback message. As mentioned by @lizhanhui, half message means prepared message, which are not visible to consumers,and it will be sent before local transaction is executed. After the local transaction ends,producer will send a commit or rollback message to broker based on local transaction execution result. when producers are blocked or crashed after send a half message,the broker will check all of producers with the same role to obtain the transaction status, so producer must implement the check listener interface to response transaction check query request.

In our implementation, we will make full use of the mechanism of rocketMQ itself to avoid external dependencies, so we will build two new system topic to store half message(RMQ_SYS_TRANS_HALF_TOPIC)and commit/rollback result message(RMQ_SYS_TRANS_OP_HALF_TOPIC),and we will also add a checkback service in broker to periodically check every message in the half message queue, if its corresponding result message can be found in the result message queue, it will be consumed or discarded depends on its result status,and if this message cannot be found in the result queue,that indicates that it was in pending status, so the checkback service will send check request to all corresponding producers to obtain transaction status, at the same time,we will also support immunity time config for producer to avoid being checked prematurely, the pending but still in immunity time message will be reload to the half message queue to wait for the next round of check.

We will submit a PR in the community, welcome to provide comments and review code.

All 6 comments

Thanks for @lizhanhui's feature request,and as mentioned above, with the rise of micro service architecture,developers are eager to use a mechanism to ensure the eventual consistency of transaction, especially in distributed systems, and we also found transaction aware message can achieve this goal gracefully, so we intend to implement this feature in rocketMQ, and this process is as follows:

transaction

In our design, we will define a pair of message: named half message and commit/rollback message. As mentioned by @lizhanhui, half message means prepared message, which are not visible to consumers,and it will be sent before local transaction is executed. After the local transaction ends,producer will send a commit or rollback message to broker based on local transaction execution result. when producers are blocked or crashed after send a half message,the broker will check all of producers with the same role to obtain the transaction status, so producer must implement the check listener interface to response transaction check query request.

In our implementation, we will make full use of the mechanism of rocketMQ itself to avoid external dependencies, so we will build two new system topic to store half message(RMQ_SYS_TRANS_HALF_TOPIC)and commit/rollback result message(RMQ_SYS_TRANS_OP_HALF_TOPIC),and we will also add a checkback service in broker to periodically check every message in the half message queue, if its corresponding result message can be found in the result message queue, it will be consumed or discarded depends on its result status,and if this message cannot be found in the result queue,that indicates that it was in pending status, so the checkback service will send check request to all corresponding producers to obtain transaction status, at the same time,we will also support immunity time config for producer to avoid being checked prematurely, the pending but still in immunity time message will be reload to the half message queue to wait for the next round of check.

We will submit a PR in the community, welcome to provide comments and review code.

  1. 队列如何对待没有提交,或者回滚的消息。
  2. 如何回滚消息,回滚消息的性能。
  3. 主从与宕机的一致性处理,宕机之后如何保证之前的消息的一致性
  4. 如果要处理一致性,是否做类似与MySQL的 rodu,undo吗?

Good catch for transactional message :-) IMO, the feature will give a awesome complementation for the SAGA pattern, and could we consider abstract the local storage in the broker? In that case, we could create a common solution for the span-multiple-service transactions in the microservice field :-) BTW, I am glad to help you to finish the feature.

when publish 4.3.0?

@zjw2011 Will you help to review the PR as the issue referred ? could be helpful for the community.

Close as this feature is merged

Was this page helpful?
0 / 5 - 0 ratings