冪等性(Idempotence)


參考:

1、冪等性的定義

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

​ 一次和多次請求某一資源應該具有同樣的影響。如果第一次請求對資源產生了副作用,以后的多次請求都不會對資源有副作用。

2、為何需要冪等性

​ 以取錢為例, withdraw(account_id, amount)是從account_id的賬號中取走amount數額的錢。但是當網絡故障或者出bug,沒有收到操作成功的OK信息。頁面請求多次提交,那么賬號就會多次扣錢。

​ 針對這個問題解決方案有兩種:

  • 分布式事務。引入分布式事務的中間件,來保證操作的事務性,保證ACID性,但是隨着中間件的引入,整體架構會更加復雜,不夠輕量,不利於異構系統的集成。
  • 冪等性設計。通過一些冪等性設計方式,解決此問題。更加輕量級。

3、解決冪等性的方式

(1)悲觀鎖

​ 獨占資源,阻塞其他需要鎖的線程。

(2)樂觀鎖

每次不加鎖,假設沒有沖突去完成某項操作,如果因為沖突失敗就重試,直到成功為止。使用的機制就是CAS(Compare and Swap),CAS有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改為B,否則什么都不做。但是存在ABA問題,可以通過version版本號自增控制。例如: UPDATE tab1 SET col1=1,version=version+1 WHERE version=#version# 當前線程如果得到的版本號不是之前拿到的,就會重試。

ABA問題:主要是針對當CAS保存的A是一個鏈表的頭指針的情況,CAS只會檢查頭指針是否變化,不會檢查這個鏈表是否有變化,從而出現問題。解決方式就是每次操作version版本號自增。

(3)去重表/唯一索引

將操作的流水單號orderNo做為去重表的唯一索引,每次請求都根據流水單號向去重表中插入一條數據。因為表中唯一索引而插入失敗,則返回操作失敗,直到第一次的請求完成(成功或失敗)。可以看出防重表作用是加鎖的功能。

(4)token令牌

int create_ticket() 
bool idempotent_withdraw(ticket_id, account_id, amount)

create_ticket的語義是獲取一個服務器端生成的唯一的處理號ticket_id,它將用於標識后續的操作。idempotent_withdraw和withdraw的區別在於關聯了一個ticket_id,一個ticket_id表示的操作至多只會被處理一次,每次調用都將返回第一次調用時的處理結果。這樣,idempotent_withdraw就符合冪等性了,客戶端就可以放心地多次調用。

idempotent

基於冪等性的解決方案中一個完整的取錢流程被分解成了兩個步驟:1.調用create_ticket()獲取ticket_id;2.調用idempotent_withdraw(ticket_id, account_id, amount)。雖然create_ticket不是冪等的,但在這種設計下,它對系統狀態的影響可以忽略,即使出現未收到token令牌也沒有關系,可以重新發請求生成令牌。加上idempotent_withdraw是冪等的,所以任何一步由於網絡等原因失敗或超時,客戶端都可以重試,直到獲得結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM