1. 程式人生 > 其它 >如何保證冪等性

如何保證冪等性

目錄

一、背景:

分散式場景下,介面的開發大都需要保證冪等性。

冪等性:一個介面被呼叫,不管幾次,產生一樣的效果,一樣返回結果。

介面呼叫過程中,很可能因為網路等原因進行重試呼叫,如果不能保證冪等性,那就完犢子了。

例如:使用者支付的介面,使用者有可能連續點選支付,總不能扣好幾次錢吧。

二、場景:

1、前端重複提交:

使用者快速重複點選多次,造成後端生成多個內容重複的資料。

2、介面超時重試:

對於給第三方呼叫的介面,為了防止網路抖動或其他原因造成請求丟失,這樣的介面一般都會設計成超時重試多次。

HTTP,RPC等在超時的情況下會有重試機制。

3、訊息重複消費:

MQ訊息中介軟體,訊息重複消費。

三、冪等性方案:

冪等性的保證,很明顯無法通過一個方案解決所有問題,只能具體場景具體分析的。

1、業務表唯一索引:

對於資料插入的場景來說,這是最常見的方案。

核心業務欄位設定為唯一索引,多次插入就會報錯,從而保證冪等性。

2、狀態流轉控制:

狀態流轉也是最常見的冪等性保證手段。

如配送業務中,騎手的操作肯定會對業務流轉狀態進行校驗。如果騎手已經提貨,那就肯定不能再次提貨的。

3、樂觀鎖版本號:

在業務表中新建一個欄位version,int型別。

服務A呼叫服務B需要更新的時候,需要提前查詢到version,然後作為引數傳過去。

如果資料更新的時候將version + 1,介面如果發生重試的時候,version已經發生變更,那麼也能保證冪等性。

PS:老實說,這個方案我本人沒用過,有點麻煩。大部分的更新不需要保證冪等性,最終的資料也能保證一致。

4、去重:

對於前端呼叫的介面,有些場景無法通過前面的方案保證冪等性。

介面中可以新增一個引數,這個引數保證每次請求都是唯一的。

然後將這個引數儲存,每次請求的入參校驗都會查詢這個引數是否存在,如果存在就返回。

引數儲存的方案可以是MySQL或者Redis。

對於本身併發較低的場景,不會對MySQL服務造成壓力,可以直接使用MySQL。否則,就要考慮Redis了,Redis這個key設定超時時間不用太長。

5、分散式鎖:

考慮到分散式環境下,很多方案的校驗如果無法保證序列的情況下,還是無法保證冪等性的。

例如,前面的狀態機校驗,併發環境下,可能還是會有問題,所以具體場景再進行分析。