介面的冪等性怎麼設計?

2022-02-10 14:55:27 字數 1980 閱讀 7614

一、什麼是冪等?

看一下維基百科怎麼說的:

冪等性:多次呼叫方法或者介面不會改變業務狀態,可以保證重複呼叫的結果和單次呼叫的結果一致。

二、使用冪等的場景

1、前端重複提交

使用者註冊,使用者建立商品等操作,前端都會提交一些資料給後台服務,後台需要根據使用者提交的資料在資料庫中建立記錄。如果使用者不小心多點了幾次,後端收到了好幾次提交,這時就會在資料庫中重複建立了多條記錄。這就是介面沒有冪等性帶來的 bug。

2、介面超時重試

對於給第三方呼叫的介面,有可能會因為網路原因而呼叫失敗,這時,一般在設計的時候會對介面呼叫加上失敗重試的機制。如果第一次呼叫已經執行了一半時,發生了網路異常。這時再次呼叫時就會因為髒資料的存在而出現呼叫異常。

3、訊息重複消費

在使用訊息中介軟體來處理訊息佇列,且手動 ack 確認訊息被正常消費時。如果消費者突然斷開連線,那麼已經執行了一半的訊息會重新放回佇列。

當訊息被其他消費者重新消費時,如果沒有冪等性,就會導致訊息重複消費時結果異常,如資料庫重複資料,資料庫資料衝突,資源重複等。

三、解決方案

1、token 機制實現

通過token 機制實現介面的冪等性,這是一種比較通用性的實現方法。

示意圖如下:

具體流程步驟:

客戶端會先傳送乙個請求去獲取 token,服務端會生成乙個全域性唯一的 id 作為 token 儲存在 redis 中,同時把這個 id 返回給客戶端

客戶端第二次呼叫業務請求的時候必須攜帶這個 token

服務端會校驗這個 token,如果校驗成功,則執行業務,並刪除 redis 中的 token

如果校驗失敗,說明 redis 中已經沒有對應的 token,則表示重複操作,直接返回指定的結果給客戶端

注意:對 redis 中是否存在 token 以及刪除的**邏輯建議用 lua 指令碼實現,保證原子性

2、基於 mysql 實現

這種實現方式是利用 mysql 唯一索引的特性。

示意圖如下:

具體流程步驟:

建立一張去重表,其中某個字段需要建立唯一索引

客戶端去請求服務端,服務端會將這次請求的一些資訊插入這張去重表中

因為表中某個字段帶有唯一索引,如果插入成功,證明表中沒有這次請求的資訊,則執行後續的業務邏輯

如果插入失敗,則代表已經執行過當前請求,直接返回

3、基於 redis 實現

這種實現方式是基於 setnx 命令實現的

setnx key value:將 key 的值設為 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 setnx 不做任何動作。

該命令在設定成功時返回 1,設定失敗時返回 0。

示意圖如下:

具體流程步驟:

總結

這幾種實現冪等的方式其實都是大同小異的,類似的還有使用狀態機、悲觀鎖、樂觀鎖的方式來實現,都是比較簡單的。

總之,當你去設計乙個介面的時候,冪等都是首要考慮的問題,特別是當你負責設計轉賬、支付這種涉及到 money 的介面,你要格外注意嘍!

介面的冪等性

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

介面的冪等性

乙個操作,無論執行多少次,產生的效果和返回的結果都是一樣的.查詢和刪除操作具有天然的冪等性,新增和修改需要保證冪等性.在redis中儲存token實現冪等性 當客戶端需要請求新增或修改介面時,需要先向伺服器請求token 伺服器接收到客戶端請求token的請求,生成token並儲存在redis中,然...

介面的冪等性

介面冪等性就是使用者對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因為多次點選而產生了 舉個最簡單的例子,那就是支付,使用者購買商品後支付,支付扣款成功,但是返回結果的時候網路異常,此時錢已經扣了,使用者再次點選按鈕,此時會進行第二次扣款,返回結果成功,使用者查詢餘額返發現多扣錢了,流水...