1. 程式人生 > 其它 >冪等性問題以及解決方案

冪等性問題以及解決方案

冪等性問題以及解決方案

目錄

1、問題

  • 說一說什麼是冪等?
  • 如何去解決冪等性問題?

2、回答

2.1、說一說什麼是冪等?

先給予名詞上的解釋:所謂冪等,其實它是一個數學上的概念。

我們認知的解釋:而在計算機程式設計領域呢,冪等一般是指方法被多次執行的時候所產生的影響和其第一次產生的影響是相同的

為什麼會存在:

之所以要考慮冪等性問題,是因為在網路通訊裡存在兩種行為可能會導致介面被重複呼叫

  • 不可控因素:使用者的重複提交或惡意攻擊,導致請求重複
  • 為了解決另外的問題所導致的:在分散式架構中,為了避免網路通訊導致的資料丟失,在服務之間進行通訊的時候,一般都會設計超時重試這樣一個機制,而這種機制有可能導致服務端介面被重複呼叫

所以對於資料變更類的介面(一般情況下查詢和刪除操作有天然的冪等性),我們要保證介面的冪等性,而其核心思想就是保證這個介面只執行一次,後續再次呼叫也不能對資料產生任何的影響。

2.2、那麼,我們對於這冪等性問題,有什麼解決方案呢?

2.2.1、唯一索引

唯一索引:使用資料庫唯一約束實現冪等,比如對於資料插入類場景,假如是建立訂單,訂單id肯定是唯一的,給訂單id加上唯一索引,那麼我們在多次建立訂單時,會觸發資料庫的唯一約束異常,這樣就保證不管是以何種方式落庫,資料庫的記錄都具有唯一性。

2.2.2、Redis命令

Redis命令:使用Redis裡面提供的setNX指令,比如對於為了避免MQ重複消費導致多次資料被修改,我們可以在訊息到資料時,把這個訊息通過setNx寫入到Redis中,一旦這個訊息被消過,就不會再次消費(過期時間由業務決定)

2.2.3、狀態機

狀態機:使用狀態機來實現冪等,所謂的狀態機是指一條資料的完整執行狀態的轉換流程,比如訂單狀態,因為他的狀態只會向前變更,所以多次修改同一條資料的時候,一旦狀態發生變更,那麼對這條資料修改造成的影響只發生一次

2.2.4、token

token:資料提交前要向服務的申請token,token放到redis或jvm記憶體,token需要設定有效時間,一般我們一個請求從request到respond時間是很短的,所以有效時間可以設定短一點;(分散式場景下鎖要第三方提供的)

提交到後臺校驗token,同時刪除token,返回執行結果。token特點:一次有效性,用完即刪,可以限流執行。

2.2.5、悲觀鎖

悲觀鎖:獲取資料的時候加鎖獲取。

 select * from t_name where id='xxx' for update; 

注意:這邊的id欄位一定是主鍵或者唯一索引,不然會導致鎖表。悲觀鎖使用時一般會配合事務一起使用,資料鎖定時間可能會很長,根據實際情況選用。 具體詳情可以看:大佬連結

2.2.6、樂觀鎖

樂觀鎖:樂觀鎖只是在更新資料那一刻鎖表,其他時間不鎖表,所以相對於悲觀鎖,效率更高,適用於多讀少寫的型別,併發大的情況。

樂觀鎖的實現方式多種多樣,可以通過version或者其他狀態條件:

  1. 通過版本號實現
update t_name set name=#{name},version=version+**1** where version=#{version}; 
  1. 通過條件限制
update t_name set avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >= 0

使用版本號的方式執行過程如下圖:

這邊需要注意: 樂觀鎖的更新操作,如果加上主鍵或者唯一索引來作為條件, 更新時鎖的是行,否則更新時會鎖表,效能效率差很多。所以上面兩個sql改成下面兩個會好很多。

update t_name set name=#name#,version=version+1 where id=#id# and version=#version#;
update t_name set avai_amount=avai_amount-#subAmount# where id=#id# and avai_amount-#subAmount# 

參考連結:

https://heapdump.cn/article/3145412

https://zhuanlan.zhihu.com/p/355103045

https://zhuanlan.zhihu.com/p/348316955