Home >Common Problem >How to ensure idempotence of interfaces under high concurrency
There are many operations in our actual system, which should produce the same effect or return the same result no matter how many times they are performed.
For example:
The front-end repeatedly submits the selected data, and the background should only produce one response result corresponding to this data.
When we initiate a payment request, the user account should only be deducted once. When encountering a network retransmission or a system bug reissue, the money should be deducted only once;
Sending a message should only be sent once. If the same text message is sent to the user, the user will cry;
When creating a business order, one business request can only Create one, create more than one and you'll have big problems.
and many other important situations, these logics require idempotent features to support.
Idempotence (idempotent, idempotence) is a mathematical and computer science concept that is commonly found in abstract algebra.
In programming, the characteristic of an idempotent operation is that the impact of any multiple executions is the same as the impact of one execution. An idempotent function, or idempotent method, is a function that can be executed repeatedly with the same parameters and obtain the same result.
These functions will not affect the system status, and there is no need to worry about changes to the system caused by repeated execution. For example, the "getUsername() and setTrue()" functions are idempotent functions.
The idempotence guarantee of more complex operations is achieved by using a unique transaction number (serial number).
My understanding: Idempotence is an operation. No matter how many times it is executed, the effect and the result returned are the same. It’s the same
1. Query operation If you query once or query multiple times, the query results will be the same when the data remains unchanged. Select is a natural idempotent operation
2. Delete operation The deletion operation is also idempotent. Deleting once and deleting multiple times will delete the data. (Note that the returned results may be different. If the deleted data does not exist, 0 will be returned. If there are multiple deleted data, multiple returned results will be returned.)
3. Unique index to prevent new dirty data For example: Alipay's capital account. Alipay also has user accounts. Each user can only have one capital account. How to prevent multiple capital accounts from being created for a user? Then add a unique index to the user ID in the capital account table, so a new user can add Successfully record a capital account
Key points: Use unique index or unique combined index to prevent dirty data in new data (when the table has a unique index and an error is reported when new data is added concurrently, query again That’s it, the data should already exist, just return the result)
4. Token mechanism to prevent repeated submission of pages
Business requirements:
The data on the page can only be clicked and submitted once
Cause of occurrence: Due to repeated clicks or network resends, or nginx resends, etc., the data will be submitted repeatedly.
Solution: Cluster environment: use token plus redis (redis is single-threaded, processing needs to be queued) Single JVM environment: use token plus redis or token plus jvm memory
Processing process:
Before submitting data, you must apply for a token from the service. The token is placed in redis or jvm memory. The token is valid for as long as
The token is verified in the background after submission. Delete the token at the same time, generate a new token and return
Token features:
To apply, it is valid once, and the current can be limited
Note: redis requires Use the delete operation to judge the token. Successful deletion means that the token verification has passed. If you use select delete to verify the token, there will be concurrency problems. It is not recommended to use
5. Pessimistic lock Obtain data Time to lock and get
select * from table_xxx where id='xxx' for update;
Note: The id field must be the primary key or the only index, otherwise the table will be locked, which will kill people
Use pessimistic lock Usually used together with transactions, the data locking time may be very long, choose
#6 according to the actual situation. Optimistic lock Optimistic lock only locks the table at the moment when the data is updated, and does not lock at other times. table, so it is more efficient than pessimistic locking.
Optimistic locking can be implemented in various ways through version or other status conditions:
1. Implementation through version number
update table_xxx set name=#name#,version=version+1 where version=#version#
As shown below (from the Internet):
2. Through conditional restriction
update tablexxx set avaiamount=avaiamount-#subAmount# where avaiamount-#subAmount# >= 0
Requirement: quality-#subQuality# >=, this scenario is suitable for not using a version number, and only updating is for data security verification It is suitable for inventory model, share deduction and rollback share, and has higher performance
注意:乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表,上面两个sql改成下面的两个更好
update tablexxx set name=#name#,version=version+1 where id=#id# and version=#version#update tablexxx set avaiamount=avaiamount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0
7. 分布式锁 还是拿插入数据的例子,如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定
这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁
这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。
要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)
8. select + insert 并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了
注意:核心高并发流程不要用这种方法
9. 状态机幂等 在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机
If the state machine is already in the next state, and a change to the previous state occurs at this time, the change cannot be made in theory. In this case, the idempotence of the finite state machine is guaranteed.
Note: Orders and other document-type businesses have a long state flow. You must have a deep understanding of the state machine, which will greatly help improve your business system design capabilities
10. External How does the api that provides the interface ensure idempotence
For example, the payment interface provided by UnionPay: when a merchant needs to access the merchant to submit a payment request, it is accompanied by: source source, seq serial number
source seq is in the database A unique index is made inside to prevent multiple payments (when concurrent, only one request can be processed)
Key pointsIn order to provide an external interface to support idempotent calls, the interface has two fields that must be passed. One is the source, and the other is the source serial number seq. These two fields are used as a joint unique index in the provider system
In this way, when a third party calls, first check in the own system to see if it has been If it has been processed, the corresponding processing result will be returned; if it has not been processed, the corresponding processing will be performed and the result will be returned.
Note that in order to be idempotent and friendly, you must first query whether the business has been processed. If you directly insert it into the business system without querying, an error will be reported, but it has actually been processed.
Idempotence should be a gene of a qualified programmer. When designing a system, it is the primary consideration, especially in companies such as Alipay, banks, and Internet financial companies that all involve money. The system must be efficient and the data must be accurate, so problems such as excessive deductions and overpayments cannot occur. This will be difficult to handle and the user experience will not be good.
The above is the detailed content of How to ensure idempotence of interfaces under high concurrency. For more information, please follow other related articles on the PHP Chinese website!