如何保證介面的冪等性

2022-04-03 02:12:30 字數 2504 閱讀 2308

冪等性是系統服務對外一種承諾,承諾只要呼叫介面成功,外部多次呼叫對系統的影響是一致的。宣告為冪等的服務會認為外部呼叫失敗是常態,並且失敗之後必然會有重試。

介面呼叫下存在的問題:

現如今我們的系統大多拆分為分布式soa,或者微服務,一套系統中包含了多個子系統服務,而乙個子系統服務往往會去呼叫另乙個服務,而服務呼叫服務無非就是使用rpc通訊或者restful,既然是通訊,那麼就有可能在伺服器處理完畢後返回結果的時候掛掉,這個時候使用者端發現很久沒有反應,那麼就會多次點選按鈕,這樣請求有多次,那麼處理資料的結果是否要統一呢?那是肯定的!尤其在支付場景。

乙個場景:

假如客戶賬戶account1現在有100元,執行一次交易(order01)扣款10元,現在有就變成了90元,在分布式情況下,假如網路超時失敗之類的情況下,就會導致可能客戶端拿到了timeoutexception,但是實際上server端執行成功了,這時客戶端可能會發起重試,或者用mq處理的話,mq會重試。如果再執行一次就扣款10元,就變成了80元,顯然這是不對的。況且如果重試操作發生了多次,餘額被扣成了負數。理想的狀態就是,多次的重複處理,結果應該不變,還是90元。

天然冪等操作

1、查詢操作:查詢一次和查詢多次,在資料不變的情況下,查詢結果是一樣的。select是天然的冪等操作;

2、刪除操作:刪除操作也是冪等的,刪除一次和多次刪除都是把資料刪除。(注意可能返回結果不一樣,刪除的資料不存在,返回0,刪除的資料多條,返回結果多個) ;

3、唯一索引:防止新增髒資料。比如:支付寶的資金賬戶,支付寶也有使用者賬戶,每個使用者只能有乙個資金賬戶,怎麼防止給使用者建立資金賬戶多個,那麼給資金賬戶表中的使用者id加唯一索引,所以乙個使用者新增成功乙個資金賬戶記錄。要點:唯一索引或唯一組合索引來防止新增資料存在髒資料(當表存在唯一索引,併發時新增報錯時,再查詢一次就可以了,資料應該已經存在了,返回結果即可)

token機制: 防止頁面重複提交

1、服務端提供了傳送token的介面。我們在分析業務的時候,哪些業務是存在冪等問題的,就必須在執行業務前,先去獲取token,伺服器會把token儲存到redis中。

2、然後呼叫業務介面請求時,把token攜帶過去,一般放在請求頭部。

3、伺服器判斷token是否存在redis中,存在表示第一次請求,然後刪除token,繼續執行業務。

4、如果判斷token不存在redis中,就表示是重複操作,直接返回重複標記給client,這樣就保證了業務**,不被重複執行。

關鍵點 先刪除token,還是後刪除token。

後刪除token:如果進行業務處理成功後,刪除redis中的token失敗了,這樣就導致了有可能會發生重複請求,因為token沒有被刪除。這個問題其實是資料庫和快取redis資料不一致問題,後續會寫文章進行講解。

先刪除token:如果系統出現問題導致業務處理出現異常,業務處理沒有成功,介面呼叫方也沒有獲取到明確的結果,然後進行重試,但token已經刪除掉了,服務端判斷token不存在,認為是重複請求,就直接返回了,無法進行業務處理了。

先刪除token可以保證不會因為重複請求,業務資料出現問題。出現業務異常,可以讓呼叫方配合處理一下,重新獲取新的token,再次由業務呼叫方發起重試請求就ok了。

token機制缺點

業務請求每次請求,都會有額外的請求(一次獲取token請求、判斷token是否存在的業務)。其實真實的生產環境中,1萬請求也許只會存在10個左右的請求會發生重試,為了這10個請求,我們讓9990個請求都發生了額外的請求。

樂觀鎖機制:基於版本號version實現, 在更新資料那一刻校驗資料

這種方法適合在更新的場景中,update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1

根據version版本,也就是在操作庫存前先獲取當前商品的version版本號,然後操作的時候帶上此version號。我們梳理下,我們第一次操作庫存時,得到version為1,呼叫庫存服務version變成了2;但返回給訂單服務出現了問題,訂單服務又一次發起呼叫庫存服務,當訂單服務傳如的version還是1,再執行上面的sql語句時,就不會執行;因為version已經變為2了,where條件就不成立。這樣就保證了不管呼叫幾次,只會真正的處理一次。

樂觀鎖主要使用於處理讀多寫少的問題。

唯一主鍵(唯一索引):防止新增髒資料

這個機制是利用了資料庫的主鍵唯一約束的特性,解決了在insert場景時冪等問題。但主鍵的要求不是自增的主鍵,這樣就需要業務生成全域性唯一的主鍵。

如果是分庫分表場景下,路由規則要保證相同請求下,落地在同乙個資料庫和同一表中,要不然資料庫主鍵約束就不起效果了,因為是不同的資料庫和表主鍵不相關。

唯一id

呼叫介面時,生成乙個唯一id,redis將資料儲存到集合中(去重),存在即處理過,這種是強校驗場景,比如和金錢相關的場景,唯一id號可以當作乙個訂單號。

如何保證介面的冪等性

冪等性是系統服務對外一種承諾,承諾只要呼叫介面成功,外部多次呼叫對系統的影響是一致的。宣告為冪等的服務會認為外部呼叫失敗是常態,並且失敗之後必然會有重試。以sql為例 select col1 from tab1 wher col2 2,無論執行多少次都不會改變狀態,是天然的冪等。update tab...

如果保證介面的冪等性

冪等性原本是數學上的概念,即公式 f x f f x 能夠成立的數學性質 那麼在程式設計領域,為對乙個系統,使用同樣的條件,一次請求和重複的多次請求對系統資源的影響是一致的。冪等性是分布式系統設計中非常重要的概念,具有這一性質的介面在設計時總是秉持這樣的一種理念 呼叫介面發生異常並且重複嘗試時,總是...

如何保證微服務介面的冪等性

在微服務架構下,我們在完成乙個訂單流程時經常遇到下面的場景 乙個訂單建立介面,第一次呼叫超時了,然後呼叫方重試了一次 在訂單建立時,我們需要去扣減庫存,這時介面發生了超時,呼叫方重試了一次 當這筆訂單開始支付,在支付請求發出之後,在服務端發生了扣錢操作,介面響應超時了,呼叫方重試了一次 乙個訂單狀態...