Implementing distributed transactions with message systems

Source: Internet
Author: User
Tags commit one table prepare rollback ticket

From Alipay to transfer 10,000 dollars to the balance of treasure, which is a common matter of daily life, but as the Internet research and development personnel of the occupational disease, I think the Alipay deduction after 10,000, if the system hangs up how to do, then the balance treasure account does not increase 10,000, the data will appear inconsistent status.

The above scenes in each type of system can find similar shadow, such as in the e-commerce system, when a user orders, in addition to inserting a record in the order table, the corresponding commodity table of this product quantity must be reduced by 1, how to guarantee. In the search advertising system, when the user clicks on an ad, in addition to adding a record in the Click event table, you also have to go to the Merchant Account table to find the merchant and deduct the advertising fee, how to guarantee. And so on, I believe that you can encounter similar situations in many or more places.

In essence, the problem can be abstracted: how to ensure that the data of another table must be updated successfully when one table data is updated. 1. Local affairs

Or take the Alipay transfer balance as an example, assuming that:
-Alipay Account form: A (Id,userid,amount)
-Balance Treasure Account form: B (Id,userid,amount)
-User's userid=1;

The action of transferring 10,000 dollars from Alipay to balance treasure is divided into two steps:
-1) Alipay deduction 10,000: Update A set amount=amount-10000 where userid=1;
-2) Balance Treasure table added 10,000: Update B set amount=amount+10000 where userid=1;
How to make sure the Alipay balance is balanced. Some people say this is very simple, can be resolved with a transaction.


Begin Transaction
Update A set amount=amount-10000 where userid=1;
Update B set amount=amount+10000 where userid=1;
END Transaction
Commit
 

It's true that if you use spring, an annotation will take care of the above transaction functionality.

@Transactional (rollbackfor=exception.class) public
    Void Update () {
        updateatable ();//update a table
        updatebtable (); Update b Table
    }

If the system is small and the data tables are on a DB instance, the local transaction method can run well, but if the system is large, such as the Alipay Account table and the Balance Treasure Account table are obviously not on the same db instance, they tend to be distributed on different physical nodes, and the local transaction has lost its place.

Since local transactions fail, distributed transactions naturally mount on the stage. 2. Distributed transaction-two phase commit protocol

The two-phase commit protocol (two-phase commit,2pc) is often used to implement distributed transactions. Generally divided into Coordinator C and a number of transaction performers si two roles, where the transaction executor is a specific database, the coordinator can and transaction executor on a machine.

1) Our application (client) initiates a start request to TC;
2) TC First writes the <prepare> message to the local log, then initiates the <prepare> message to all Si. To pay treasure transfer to the balance of treasure for example, TC to a prepare message is to inform the Alipay database corresponding account deduction 10,000, TC to b prepare message is to inform the balance of the database corresponding accounts increase 1w. Why do you need to write the local log before the task, mainly for the recovery after the failure, the local log to the real life of the effect of the voucher, if there is no local log (voucher), the problem is easy to Chenghua;
3) SI receives <prepare> message, executes the specific native transaction, but does not commit, if returns <YES> successfully, does not return <no> successfully. In the same vein, the message to be returned should be written to the log as a voucher before returning.
4) TC collects all the messages returned by the actuator, and if all the actuators return yes, a commit message is sent to all the actuators, and the executor receives a commit of the local transaction after the commit, and if any of the actuators returns no, the abort message is sent to all the actuators. , the executor performs a transaction abort operation after receiving the abort message.

NOTE: TC or SI to send or receive the message first written to the log, mainly for the recovery after the failure. If an SI recovers from a failure, first check the log of the machine, if it has received <commit>, then commit, if <abort rollback. If it is <yes>, then ask TC again to determine the next step. If there is nothing, it is likely that SI will crash in the <prepare> phase, so it needs to be rolled back.

It's not that difficult to implement distributed transactions based on two-phase commits today, and if you use Java, you can use open source software Atomikos to quickly implement it.

However, anyone who has used these two-stage submissions can find that the performance is too poor to be suitable for high-concurrency systems at all. Why.
1) Two-phase commit involves multiple nodes of network communication, the communication time is too long.
2) transaction time is longer than the time of the lock, and the resource waiting time is also increased.
3. Use Message Queuing to avoid distributed transactions

If we look closely at life, many scenes of life have given us hints.

For example, in Beijing is famous Yao Kee soy point soy and pay the money, they will not direct your point soy to you, but give you a small ticket, and then let you take the small ticket to the shipping area line to take. Why should they separate the two movements of the payment and the pickup? For many reasons, one of the important reasons is to enhance their reception capacity (concurrency is higher).

Return to our question, as long as this small ticket in, you finally can get soy. Similarly, when the Alipay account is deducted 10,000, we just generate a voucher (message), the voucher (message) says "Let balance treasure account increase 10,000", as long as this voucher (message) can be reliably saved, we can finally hold this voucher (message) to the balance treasure account to increase 10,000, That is, we can rely on this credential (message) to achieve final consistency. 3.1. How to reliably save messages

There are two ways to do this: 3.1.1 business with message coupling

Alipay, while completing the debit, simultaneously records the message data, which is stored in the same DB instance as the business data (the message log table name is a note).

Begin Transaction
         Update A set amount=amount-10000 where userid=1;
         INSERT into message (USERID, Amount,status) VALUES (1, 10000, 1);
END transaction
commit;

The above transaction can guarantee that the information will be preserved as long as the money is deducted from the Alipay account.

When the above-mentioned transaction is successfully submitted, we will notify the balance treasure through the real-time message service, and send a reply success message after the successful processing of the balance treasure, the Alipay receives the reply and deletes the message data. 3.1.2 Service and message decoupling method

The way in which messages are saved makes the message data and business data tightly coupled, architecturally elegant, and prone to other problems. To understand decoupling, you can use the following methods.

1) Alipay sends a message to the real-time message service request before the debit transaction is submitted, and the real-time message service logs only the message data, not the actual sending, and the transaction is not committed until the message is sent successfully;

2) when the Alipay debit transaction is successfully submitted, confirm the delivery to the real-time message service. The real-time message service sends the message only after it has been confirmed to send the command.

3) Cancel the delivery to the real-time messaging service after a failed rollback of Alipay transaction submission. The message will not be sent after the cancellation command is received;

3) Cancel the delivery to the real-time messaging service after a failed rollback of Alipay transaction submission. The message will not be sent after the cancellation command is received;

4) For those unacknowledged messages or canceled messages, a message status confirmation system is required to check the status of the message and update it periodically. Why this step is needed, for example: assuming that after the 2nd step Alipay transaction was successfully submitted, the system hangs, and the message status is not updated to "confirm send", which causes the message not to be sent.

Advantages: The independent storage of message data reduces the coupling between the business system and the message system;

Cons: Two requests are required for one message to be sent, and the business processing service needs to implement the message state callback interface. 3.2, how to solve the problem of repeated delivery of messages

Another very serious problem is the repeated delivery of the message, with our Alipay transfer to the balance of treasure for example, if the same message is repeated two times, then our balance treasure account will be increased by 20,000 instead of 10,000.

Why the same message will be delivered repeatedly. For example, the balance of Treasure Processing message MSG, sent a successful message to Alipay, under normal circumstances Alipay should be deleted MSG, but if the payment of the tragedy of this time the tragic hanging, restart after a look at the message msg is still in, will continue to send messages Msg.

The solution is very simple, in the balance Treasure side Add the Message Application state table (message_apply), popular is a ledger, used to record the consumption of messages, each time a message, before the actual execution, first go to the Message Application state table query again, if the description is a duplicate message, discard it, If it is not found, it is executed and inserted into the Message Application state table (same transaction).

For each msg in the queue
  Begin transaction
    SELECT COUNT (*) as CNT from message_apply where msg_id=msg.msg_id;
    If cnt==0 then
      update B set amount=amount+10000 where userid=1;
      Insert into message_apply (msg_id) values (msg.msg_id);
  END transaction
  commit;

This article is reproduced from http://blog.jobbole.com/89140/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.