I remember a long time ago, I mentioned in a blog about the difference between network http protocol post and put, one of the differences between the two is idempotence. It was said that post requests were non-idempotent, and put requests were idempotent. So how should idempotence be understood? I will do some sharing below, and welcome the big guys to actively participate in the discussion where something is wrong.
One, the interface is idempotent
Idempotence: Regarding the definition of idempotence, in fact, for the same behavior, the result of our operation multiple times is the same as the result of the operation once. Idempotence is actually data consistency and transaction integrity.
Then the understanding of interface idempotence is that the interface can support repeated calls, and the results produced by repeated calls are consistent. This is especially important for payment-related projects. If the interface of payment-related projects does not guarantee idempotence, it may cause serious consequences.
The payment interface must be designed to be idempotent: if the programmer accidentally designs a non-idempotent interface for payment operations. Then it may happen that the user pays when purchasing the product. After the payment is successful, the system performs a deduction operation, but the network is abnormal at this time. When the network is restored, the user clicks to submit again, although the purchase is successful, but (non-power The user will be deducted once again! ! When this happens, how can users rest assured to use it? ? Everyone hopes that the same order will only be deducted once, so it is necessary to design an idempotent interface for the payment interface.
2. Guarantee idempotence
In fact, some operations are naturally idempotent . For example, database query operation is a classic idempotent behavior, because no matter how many times you do it, it can only return one result; get, put, and delete in the network are also natural idempotent operations, which can guarantee only Return the only result.
But for operations that are not idempotent, we still have to face the problem of ensuring that the interface is idempotent. The specific operation methods are summarized as follows:
1. The database guarantees a globally unique index
We can generate a global ID based on the operation and content of the relevant business, and check whether the global unique ID exists before each operation to determine whether the operation has been executed. If the search does not exist, store the global ID in the database; if it already exists, it means that the method has been executed and the query result can be returned directly.
Then we can use this unique id to ensure that the processing logic and execution effect of the same business operation repeated many times later are consistent. The use of a globally unique ID is a general scheme to ensure idempotence, and it can support insert, update, and delete business operations. This scheme is easy to understand, but it is more troublesome to implement, and there are hidden dangers-->
Because the above guarantee idempotence scheme is divided into two steps, step ② (query) depends on the result of step ① (generation) for operation. Guaranteed atomicity. Under high concurrency, the following situation will occur: the second request arrives when the order status in step ② of the first request has not been modified to the'paid status', resulting in the result still not expected. Now that this conclusion is reached, solving this problem has become simple: lock the query and change state operations, and change the parallel operation to serial operation.
2. Optimistic lock
Optimistic locking means that every time we update data, we think that this operation will not cause data loss, so we only lock the table at the moment the data is updated, and do not lock the table at other times.
The specific implementation is to add a field version (version number) or other status bits in the database table. When operating on the table, take out the data and the flag bit version at the same time. When the data table is to be modified, it is judged whether the version is consistent with the one taken out before. If it is consistent, modify it, and if it is inconsistent, do not modify it. At the same time, it is best to ensure that the version is stored in the database through auto-increment.
Note: The update operation of optimistic locking is best to use the primary key or unique index to update, so that only one row is locked during the operation, otherwise the update operation will cause the table to be locked.
3. Use the state mechanism
When we design the business of a project, we will definitely involve the state machine (state change diagram), which is the state displayed on the business document. The state will change according to different situations. Generally, it is a limited state machine. If the state machine is already in the next state, a change request for the previous state comes at this time, and theoretically it cannot be changed. In this case, the idempotency of the finite state machine is guaranteed.
4.token token
This method is divided into two stages: the token application stage and the payment stage. In the first stage, before entering the order submission page, the order system needs to initiate a token request to the payment system based on user information. The payment system saves the token in the Redis cache and uses it for the second stage of payment. In the second stage, the order system initiates a payment request with the applied token, and the payment system checks whether the token exists in Redis. If it exists, it means that the first payment request is initiated. After the token in the cache is deleted, the payment logic processing starts; if cached Does not exist, indicating an illegal request. In fact, the token here is a token, and the payment system confirms the operation authority based on the token. The disadvantage is that it requires two interactions between systems, and the process is more complicated than the above method.
5. Payment cache
The payment request of the order is quickly followed by a buffer pipeline for quick order acceptance. Subsequent use of asynchronous tasks to process data in the pipeline to filter out repeated pending orders. The advantage is synchronous to asynchronous, high throughput. The disadvantage is that the payment result cannot be returned in time, and the asynchronous return of the payment result needs to be monitored subsequently.
Three, summary
Idempotence has nothing to do with whether the program is distributed high concurrency or JavaEE. The key is whether our operation is idempotent. An idempotent operation is typically such as: setting the A field of the record numbered 5 to 0. This operation is idempotent no matter how many times it is performed. A typical non-idempotent operation is: increasing the A field of the record numbered 5 by 1. This operation is obviously not idempotent. To achieve idempotence, no non-idempotent operations are designed in terms of interface design. For example, the requirement is: when the user clicks like, the number of approvals for the answer is +1. Change to: When the user clicks like, make sure there is a record in the answer approval form, user, answer. The number of approvals is counted by the answer approval table. In short, idempotence should be a gene of qualified programmers. When designing a system, it is the primary consideration, especially in systems that involve money such as Alipay, banks, and Internet finance companies. It must be efficient and data. It must be accurate, so there can be no problems such as excessive deductions and excessive payments. This will be difficult to handle and the user experience is not good. So if you don’t pay attention to the guarantee of interface idempotence, then the boss of the company should have opinions on you, hahh~
PS: I'm still back. This knowledge will not be forgotten for a long time, so it is really necessary to keep a good note~~