軟件開發過程中,系統的冪等性有哪些實現方案?

低調的牛肉


冪等性的概念

用戶同一操作請求了一次或者多次,最終的結果應該是一致的,並不會因為多次請求產生副作用;冪等操作的特點是“多次執行所產生的結果與一次執行的結果相同”。比如:

  • 付款操作的時候,請求已經發送給服務端,但是由於網絡原因未收到付款結果(實際上已成功),再次操作付款的時候,不應該成功;

  • 在頁面做新建操作的時候,手抖連點了新增按鈕,那麼應該只會創建出一條數據;

查詢和刪除

查詢和刪除操作,天然具有冪等性;也就是多次執行查詢或刪除操作的時候,結果和執行一次查詢或刪除的結果是一樣的。

但是要注意,多次執行刪除的返回內容可能不同,比如第一次刪除成功,後面再執行刪除的話,會顯示數據不存在。

保證冪等性的方案

新增和修改,如果不做冪等性處理,可能就會產生問題(如果修改只是把某些字段更新成固定的值,不會有冪等性問題,但是如果新值要在舊值上做處理做計算,如增加多少、減少多少,那麼多次執行的結果就會有差異);那麼保證冪等性有哪些方案呢?(給出我知道的方案,方案有好有壞)

  • 悲觀鎖:獲取數據的時候加鎖獲取;select * from table where col='xxx' for update; 只能說是一種實現方案,但是不是特別好;

  • 樂觀鎖:在更新數據那一刻鎖表,可以通過條件限制,也可以通過版本號來實現,比如:數據中增加版本號的概念,那麼在做數據修改,把當前數據的版本號帶上,修改的時候要按照版本號判斷數據是否發生過更改。如果沒有發生過更改,則執行業務操作,並更新版本號。

  • 分佈式鎖:在業務系統執行插入或更新操作的時候,先要獲取分佈式鎖,然後做操作,之後釋放鎖;分佈式鎖保證在一個時間內,只會有一個線程對數據進行操作;


  • 全局唯一請求ID:每一次的請求,都帶有一個全局唯一的請求ID,這個請求ID只要執行過一次就失效了:

  • 狀態冪等:如果業務流程中的每個階段,數據都有不同的狀態,那麼當數據已經處於下一個狀態的時候,這時候又來了上一個狀態的變更,是不會執行成功的(其實有些類似於版本號的概念,不過這個狀態是有業務含義的)。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


會點代碼的大叔


1 冪等含義

操作一次和操作多次結果一致被稱為冪等。下面我們來分析幾種常用冪等方案。


2 冪等表方案

場景:用戶支付成功(訂單ID=aaa)此時支付系統將支付成功的消息,發送至消息隊列。物流系統訂閱到這個消息,準備為這筆訂單創建物流單。

但是消息隊列有可能會重複推送,也就是說物流系統有可能接收到多次這條消息。我們希望達到的效果是:無論接收到多少條重複消息,只能創建一筆物流單。

方案:新建一張冪等表,該表就是用來做冪等的,無其它業務意義。該表有一個字段名為key,建有唯一索引,這個字段是冪等的標準。

當物流系統訂閱到消息後,在創建物流單前,首先要將訂單ID(本例=aaa)嘗試插入冪等表的key字段。如果插入成功則繼續做業務。不成功表示已經處理過了,丟棄消息。

這張表所有業務都可以操作,數據量會很大,需要定期清理,並將數據備份。

當然可以利用分佈式鎖鎖住訂單ID,判斷是否已經有物流訂單了,沒有就創建物流訂單。這種方法本質上是在解決併發問題。


3 狀態機方案

場景:物流單處理成功,發送消息給訂單系統,讓訂單更新狀態為完成,假設操作是將訂單status=0更新至status=1。同理訂單系統也可能收到多條消息。

方案:使用狀態機方案:status=0只能流轉至status=1轉態,並且status=1已經是最終態。當訂單為status=1時,即使接收到物流單成功的消息也不在處理,丟棄消息。


4 樂觀鎖方案

(1) 先查出數據,數據中包含字段version

(2) 發送業務操作更新語句:update xxx set xxx,version = #{version} + 1 where id = #{id} and version = #{version}

(3) 如果此時該記錄已經被修改,version就已經發生了變化,不能被更新成功


敬請關注

請點擊關注按鈕【IT徐胖子】會持續為大家奉獻互聯網和技術乾貨內容,感謝支持


IT徐胖子


1.對每次請求生成請求id,進行防重複,redis或者應用內緩存防重

2.很多請求本身就是冪等的,比如update指定的where條件,加版本樂觀鎖


分享到:


相關文章: