In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)05/31 Report--
How to analyze distributed transactions, I believe that many inexperienced people are at a loss about this. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.
Preface
Affairs must be no stranger to everyone, as for what is ACID, it is also a clich é. However, in order to ensure the integrity of the article and make sure that everyone can understand it, I still have to talk about ACID first, and then introduce what distributed transactions and common distributed transactions are, including 2PC, 3PC, TCC, local message table, message transaction, best effort notification.
Business
Strictly speaking, the transaction implementation should be atomicity, consistency, isolation and persistence, referred to as ACID.
Atomicity can be understood to mean that all operations within a transaction are either performed or not performed.
Consistency (Consistency), can be understood as the data is to meet integrity constraints, that is, there will be no intermediate state of data, such as you have 400 on your account, my account has 100, you give me 200 yuan, then the money on your account should be 200, the money on my account should be 300, there will be no money on my account plus, money on your account has not been deducted in the middle state.
Isolation means that when multiple transactions are executed concurrently, they will not interfere with each other, that is, the data within one transaction is isolated to other transactions.
Durability means that after a transaction is completed, the data is saved forever, and other operations or failures after that will not affect the outcome of the transaction.
In the popular sense, the purpose of a transaction is to make some update operations either successful or fail.
At this point, some people may say, "No, Redis transactions cannot guarantee that all operations are either performed or not executed. Why is it also called a transaction?"
First of all, you need to know that general middleware will exaggerate its effect, and other teams also want to be more famous and attract more people to use their products, so we can look at it from a dialectical point of view.
Generally speaking, since they dare to say what they have achieved, they either really achieve it, or they can only meet the function under some special, customized or extreme conditions.
Let's see what Redis says.
This sentence is to tell everyone that a command in the transaction has failed, the subsequent command will still be processed, and Redis will not stop the command, which means it will not be rolled back.
Don't you think this is bullshit? This deviates from the core intention of the business.
Don't worry, let's see how Redis explains it.
The Redis website explains why rollbacks are not supported, saying that first of all, if the command goes wrong, it is a syntax error, it is your own programming error, and this situation should be detected at development time and should not occur in a production environment.
And then Redis is for fast! No rollback is required.
There is another paragraph below that I will not take a screenshot, that is, it is useless to provide a rollback, your code is all wrong, and a rollback will not protect you from programming errors. And generally this kind of error is impossible to enter the production environment, so choose a simpler and faster method, we do not support rollback.
You see, this seems to make a lot of sense, we do not provide rollback, because we do not need to pay for your programming errors!
But what seems to be wrong? If you have different angles and positions, you will have your own taste.
As soon as you get down, you start distributed transactions.
Distributed transaction
As the name implies, distributed transaction is to implement transaction in distributed system, which is actually composed of multiple local transactions.
For distributed transactions, it is almost impossible to meet ACID, but for stand-alone transactions, in most cases, it does not meet ACID. Otherwise, how could there be four isolation levels? So not to mention distributed transactions distributed in different databases or different applications.
Let's take a look at 2PC first.
2PC
2PC (Two-phase commit protocol), which is called two-phase submission in Chinese. The two-phase commit is a highly consistent design. 2PC introduces the role of a transaction coordinator to coordinate and manage the commit and rollback of each participant (also known as each local resource). The two-phase refers to the preparation (voting) and commit phases respectively.
Note that this is only an agreement or theoretical guidance, only describes the general direction, there will be differences in specific landing.
Let's take a look at the specific process of the next two stages.
The coordinator of the preparation phase sends a prepare command to each participant, which you can understand to mean that everything has been done except to commit the transaction.
After waiting for a response from all resources, the synchronization enters the second phase, the commit phase (note that the commit phase is not necessarily a commit transaction, or it may be a rollback transaction).
If all participants return to prepare successfully in the first phase, the coordinator sends a commit transaction command to all participants, and then returns the transaction execution after all transactions have been successfully committed.
Let's take a look at the flow chart.
If one participant returns a failure in the first phase, the coordinator sends a request to all participants to roll back the transaction, that is, the distributed transaction execution failed.
Then someone may ask, what about the failure of the second stage submission?
There are two situations.
The first is that the second phase performs a rollback transaction operation, so the answer is to keep retrying until all participants are rolled back, otherwise those who are prepared for success in the first phase will remain blocked.
The second is that the second phase carries out the commit transaction operation, so the answer is to keep retrying, because it is possible that some participants' transactions have been successfully committed, and at this time there is only one way, that is, the head iron rushes forward and keeps retrying. until the submission is successful, it can only be processed manually in the end.
In general, this is the process of two-phase submission, let's take a look at the details.
First of all, 2PC is a synchronous blocking protocol. For example, the coordinator of the first phase will wait for the response of all participants before performing the next operation. Of course, the coordinator of the first phase has a timeout mechanism. If no response from a participant is received or a participant dies due to network reasons, then the transaction failure will be judged after timeout and a rollback command will be sent to all participants.
There is no way for the coordinator to time out in the second phase, because according to our above analysis, we can only retry!
Coordinator fault analysis
The coordinator is a single point and there is a single point of failure.
Suppose the coordinator dies before sending the prepare command, which means that the transaction has not yet started.
Assuming that the coordinator dies after sending the prepare command, this is not very good, and some participants are in a state of transaction resource locking. Not only can the transaction not be executed, but also other operations of the system will be blocked because some common resources are locked.
Assuming that the coordinator dies before sending the rollback transaction command, the transaction cannot be executed, and the successful participants are blocked in the first phase.
Suppose the coordinator dies after sending the rollback transaction command, and this is OK, at least if the command is sent, there is a good chance that the rollback will be successful and resources will be released. However, if there is a network partition problem, some participants will be blocked because they cannot receive the command.
Suppose the coordinator hung up before sending the commit transaction command, this is no good, silly! Now all the resources are blocked.
Suppose the coordinator dies after sending the commit transaction command, and this is OK, or at least the command is sent out, there is a good chance that the commit will be successful, and then the resources will be freed. However, if there is a network partition problem, some participants will be blocked because they cannot receive the command.
Coordinator failure, get a new coordinator through election
Because of the single point problem of the coordinator, we can choose a new coordinator to replace it through operations such as elections.
If it is in the first stage, in fact, the impact is not mostly rolled back, and the transaction must not have been committed in the first phase.
If you are in the second stage, assuming that none of the participants are dead, the new coordinator can confirm their own situation to all participants to infer what to do next.
Suppose an individual participant is dead! This is a bit stiff, such as when the coordinator sends a rollback command, where the first participant receives and executes, and then both the coordinator and the first participant die.
At this point, none of the other participants received the request, and then the new coordinator came and asked the other participants to say OK, but it didn't know whether the dead participant was OK or not, so it was stupid.
In fact, the problem is that each participant's own state is known only to himself and the coordinator, so the new coordinator cannot infer what the dead participant is like from the status of the participants present.
Although it is not mentioned in the agreement, we can flexibly let the coordinator write down where he or she has sent the request, that is, log record, so that when the new coordinator arrives, we will know whether it is time to send it or not.
But even if the coordinator knows that he or she should submit the request, it won't work if the participants hang up together, because you don't know if the participants committed the transaction before they hung up.
If the transaction commits successfully before the participant hangs, and the new coordinator determines that the surviving participants are all right, then a commit transaction command must be sent to other participants to ensure data consistency.
If the transaction is not successfully committed before the participant hangs, and the data is rolled back after the participant resumes, the coordinator must send a rollback transaction command to other participants to keep the transaction consistent.
Therefore, in extreme cases, the problem of data inconsistency can not be avoided.
Talk is cheap lets us take another look at the code, which may be clearer. The following code is taken from.
This code implements 2PC, but compared with 2PC, it adds the action of writing logs, the participants notify each other, and the participants time out. It should be noted here that the so-called 2PC does not contain the above functions, which are added during implementation.
Coordinator: write START_2PC to local log; / / start transaction multicast VOTE_REQUEST to all participants; / / broadcast notification participants to vote while not all votes have been collected {wait for any incoming vote; if timeout {/ / coordinator timeout write GLOBAL_ABORT to local log; / / write log multicast GLOBAL_ABORT to all participants; / / notify transaction interrupt exit } record vote;} / / if all participants are ok if all participants sent VOTE_COMMIT and coordinator votes COMMIT {write GLOBAL_COMMIT to local log; multicast GLOBAL_COMMIT to all participants;} else {write GLOBAL_ABORT to local log; multicast GLOBAL_ABORT to all participants;} participant: write INIT to local log / / write log wait for VOTE_REQUEST from coordinator; if timeout {/ / wait for timeout write VOTE_ABORT to local log; exit;} if participant votes COMMIT {write VOTE_COMMIT to local log; / / record your own decision send VOTE_COMMIT to coordinator; wait for DECISION from coordinator; if timeout {multicast DECISION_REQUEST to other participants / / time-out notification wait until DECISION is received; / * remain blocked*/ write DECISION to local log;} if DECISION = = GLOBAL_COMMIT write GLOBAL_COMMIT to local log; else if DECISION = = GLOBAL_ABORT write GLOBAL_ABORT to local log;} else {write VOTE_ABORT to local log; send VOTE_ABORT to coordinator } each participant maintains a thread to process DECISION_REQUEST requests from other participants: while true {wait until any incoming DECISION_REQUEST is received; read most recently recorded STATE from the local log; if STATE = = GLOBAL_COMMIT send GLOBAL_COMMIT to requesting participant; else if STATE = = INIT or STATE = = GLOBAL_ABORT; send GLOBAL_ABORT to requesting participant; else skip / * participant remains blocked * /}
So far we have a detailed analysis of the various details of the 2PC, let's summarize it!
2PC is a distributed transaction that ensures strong consistency as far as possible, so it is synchronous blocking, while synchronous blocking leads to long-term resource locking problems, overall low efficiency, and the problem of single point of failure, and the risk of data inconsistency under extreme conditions.
Of course, specific implementations can be deformed, and 2PC also has variants, such as Tree 2PC, Dynamic 2PC.
I don't know if you have noticed that 2PC is suitable for distributed transaction scenarios at the database level, and sometimes our business requirements are not only related to the database, but also to upload a picture or send a text message.
And like JTA in Java can only solve the distributed transaction problem of multiple databases in one application, cross-service can not be used.
To put it simply, JTA in Java is a transaction interface based on XA specification. You can simply understand XA here as 2PC based on database XA specification. (as for what the XA specification is, the space is limited. We'll talk about it next time.)
Next, let's take a look at 3PC.
3PC
The emergence of 3PC is to solve some problems of 2PC. Compared with 2PC, it also introduces a timeout mechanism among participants, and adds a new phase so that participants can use this stage to unify their states.
Let's take a closer look.
3PC consists of three phases, namely, the preparation phase, the pre-commit phase and the commit phase, which correspond to CanCommit, PreCommit and DoCommit.
It seems to turn the commit phase of the 2PC into the pre-commit phase and the commit phase, but the 3PC's preparatory phase coordinator only asks the participants about their own conditions, such as how are you now? Is the load heavy? That kind of thing.
The pre-commit phase is the same as the preparation phase of 2PC, except for the commit of the transaction.
The submission phase is the same as 2PC's. Let's take a look at the diagram.
No matter which phase a participant returns a failure, the transaction is declared to fail, which is the same as 2PC (of course, in the final commit phase, like 2PC, you can only retry as long as it is a commit request).
Let's first take a look at the impact of phase changes in 3PC.
First of all, the change in the preparation phase will not execute the transaction directly, but will first ask the participants at this time whether they have the conditions to take over the transaction, so they will not work and lock resources directly. so that all participants are blocked when some resources are unavailable.
The introduction of the pre-submission stage plays the role of a unified state, which is like a fence, indicating that all participants have not responded before the pre-submission stage, and all participants have responded in the pre-submission stage.
If you are a participant and you know that you are in a pre-submitted state, you can infer that other participants are in a pre-submitted state as well.
However, the introduction of one more phase and one more interaction makes the performance worse, and in most cases the resources should be available, which means that you have to ask for each execution knowing that it is available.
Let's take a look at the impact of participants' timeouts.
We know that 2PC is synchronously blocked, and we have analyzed above that the coordinator is most vulnerable before the submission request is sent, and all participants have locked resources and blocked waiting.
Then, if the timeout mechanism is introduced, the participants will not wait foolishly. If they are waiting for the commit command to time out, then the participant will commit the transaction, because at this stage, the probability is that they will commit. If they are waiting for the pre-commit command to time out, then they will do whatever they want. Anyway, nothing has been done.
However, the timeout mechanism also brings the problem of data inconsistency, such as the timeout while waiting for the commit command, the participants default to perform the commit transaction operation, but it is possible to perform a rollback operation, so the data is inconsistent.
Of course, the 3PC coordinator timeout is still there, the specific analysis is the same as 2PC.
According to Wikipedia, the introduction of 3PC is to solve the problem that the coordinator of the new election does not know whether to submit or roll back after the 2PC coordinator and a participant are dead.
When the new coordinator arrives, it is found that one of the participants is in the pre-submission or submission stage, which indicates that it has been confirmed by all participants, so the submission command is executed at this time.
So 3PC is to unify the state among the participants by introducing the pre-submission phase, that is, leaving a phase for everyone to synchronize.
But this only lets the coordinator know if to do it, but there is no guarantee that it will be right, which is consistent with the above 2PC analysis, because it is impossible to determine whether the failed participant has executed the transaction or not.
So 3PC can reduce the complexity of failure recovery through the pre-commit phase, but there is no guarantee of data consistency unless the failed participant recovers.
Let's sum up that 3PC has made some improvements over 2PC: introducing a participant timeout mechanism and adding a pre-commit phase to reduce the decision complexity of the coordinator after fault recovery, but the overall interaction process is longer, the performance is degraded, and there will still be data inconsistencies.
Therefore, neither 2PC nor 3PC can guarantee that the data is 100% consistent, so it is generally necessary to have a timing scan compensation mechanism.
Again, I didn't find a specific implementation of 3PC, so I think 3PC is purely theoretical, and we can see that it has made some efforts compared to 2PC, but with little effect, so we can only do some understanding.
TCC
2PC and 3PC are both at the database level, while TCC is a distributed transaction at the business level. As I said earlier, distributed transactions include not only database operations, but also sending text messages. TCC will come in handy at this time!
TCC means Try-Confirm-Cancel.
Try refers to reservation, that is, the reservation and locking of resources, note that reservation is reserved.
Confirm refers to the confirmation operation, which is actually performed.
Cancel refers to the undo operation, which can be understood as undoing the action of the reservation phase.
In fact, from an ideological point of view, it is similar to 2PC, it is the first tentative implementation, if it is possible, then the real implementation, if not, rollback.
For example, if a transaction wants to perform three operations A, B, and C, then perform a reserved action on the three operations first. If all the reservations are successful, then the confirmation operation is performed, and if one reservation fails, the undo action is performed.
Let's take a look at the process. The TCC model also has the role of a transaction manager to record the TCC global transaction status and commit or roll back the transaction.
You can see that the process is still very simple, and the difficulty lies in the business definition. For each operation, you need to define three actions corresponding to Try-Confirm-Cancel.
Therefore, TCC has a large intrusion into the business and the business is tightly coupled, so it is necessary to design the corresponding operation according to the specific scenario and business logic.
It is also important to note that the execution of undo and confirmation operations may require retries, so you also need to ensure that the operations are idempotent.
Compared with 2PC and 3PC, TCC has a wider range of applications, but it also has a larger amount of development, after all, it is all implemented in business, and sometimes you will find that these three methods are really difficult to write. However, because it is implemented in business, TCC can implement transactions across databases and across different business systems.
Local message table
In fact, the local message table uses the local transactions of each system to realize distributed transactions.
The local message table, as its name implies, means that there will be a table for storing local messages, which is usually placed in the database, and then when the business is executed, the execution of the business and the operation of putting the message into the message table are placed in the same transaction. This ensures that the business will be executed successfully when the message is put into the local table.
Then call the next operation, and if the next operation invokes successfully, the message state of the message table can be changed directly to successful.
If the call fails, there will be a background task to regularly read the local message table, filter out the messages that have not been successful, and then call the corresponding service. Change the status of the message after the service update is successful.
At this time, it is possible that the operation corresponding to the message is not successful, so you need to retry to ensure that the method of the corresponding service is idempotent. In general, there will be a maximum number of retries, and if you exceed the maximum number of times, you can record the alarm and let it be handled manually.
You can see that the local message table actually achieves ultimate consistency and tolerates temporary data inconsistencies.
Message transaction RocketMQ supports message transaction very well. Let's take a look at how to implement a transaction through message.
The first step is to send a transaction message, that is, a half-message, to the Broker. The half-message does not mean that the half-message is invisible to the consumer, and then the sender executes the local transaction after it is successfully sent.
Then send Commit or RollBack commands to Broker based on the results of the local transaction.
And the sender of RocketMQ will provide an API to check the status of the transaction. If the half-message does not receive any operation request within a period of time, Broker will know whether the sender's transaction has been executed successfully through the API, and then execute the Commit or RollBack command.
If it is Commit, then the subscriber can receive the message, then do the corresponding operation, and then consume the message after it is done.
If it is RollBack, then the subscriber does not receive this message, which means that the transaction has not been executed.
You can see that it is relatively easy to implement through RocketMQ. RocketMQ provides the function of transaction messages, and we only need to define the transaction lookup interface.
You can see that the message transaction also achieves the ultimate consistency.
Best effort notification
In fact, I think the local message table can also be regarded as the best effort, and the transaction news can also be regarded as the greatest effort.
As far as the local message table is concerned, there are background tasks to check the unfinished messages regularly, and then call the corresponding service. When a message fails multiple calls, you can record it and then introduce human resources, or simply discard it. This is actually the best effort.
The same is true for transaction messages. When a semi-message is commit, it is indeed a normal message. If the subscriber does not consume or cannot consume it, it will continue to retry and finally enter the dead letter queue. In fact, this is also the best effort.
So the best effort notification only shows the idea of a flexible transaction: I have tried my best to reach a final agreement on the transaction.
It is suitable for services that are not sensitive to time, such as SMS notification.
You can see that 2PC and 3PC are strongly consistent transactions, but there are still risks of data inconsistency, blocking, and so on, and can only be used at the database level.
TCC is a compensatory transaction idea, which is more widely applicable and implemented at the business level, so it is more intrusive to the business, and each operation needs to implement the corresponding three methods.
Local messages, transaction messages, and best effort notifications are actually final consistent transactions, so they are suitable for businesses that are not time-sensitive.
After reading the above, do you know how to parse distributed transactions? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.