概述 所謂介面冪等性就是:在特定場景下,同一條件的多次介面調用,保證操作只執行一次,如果介面沒有保證冪等性,在以下場景就會產生問題 前端重覆提交:用戶進行註冊、創建個人信息等操作,由於網路抖動導致頁面沒有及時響應,用戶認為沒有成功而多次點擊提交按鈕,發生重覆提交表單請求 介面超時重試:提供外部系統調 ...
概述
所謂介面冪等性就是:在特定場景下,同一條件的多次介面調用,保證操作只執行一次,如果介面沒有保證冪等性,在以下場景就會產生問題
- 前端重覆提交:用戶進行註冊、創建個人信息等操作,由於網路抖動導致頁面沒有及時響應,用戶認為沒有成功而多次點擊提交按鈕,發生重覆提交表單請求
- 介面超時重試:提供外部系統調用的介面,因為網路抖動等原因執行成功但沒能及時響應,外部系統發起重試,導致重覆調用
- 消息重覆消費:使用消息中間件時,消費者手動 ack 確認消息被正常消費時,消費者突然斷開連接,已經執行的消息會重新放回隊列,被其他消費者重新消費
如何實現介面冪等性?
1. 防重 Token 令牌
具體流程如下:
- 客戶端獲取 token,服務端將 token 保存在 redis 中,token 需保證全局唯一
- 之後客戶端發起請求時必須攜帶 token
- 服務端校驗 token,如果成功則執行業務,並刪除 redis 中的 token,否則為重覆操作,直接返回結果
這種方式需保證同一請求都攜帶同一 token,比如同一訂單的支付操作都使用同一 token 請求。另外,在併發情況下,Redis 查找數據與刪除需要保證原子性,可以使用或 Lua 腳本保證
2. 使用 Redis 實現
這種實現方式是基於 redis 的 setnx 命令實現的,作用是如果 key 不存在,將 key 賦值為 value 並返回 1,若 key 已存在,則不做操作並返回 0
具體流程如下:
- 客戶端請求服務端,將能代表這次請求的唯一標識以 setnx 的方式存入 redis,並根據業務設置相應的超時時間
- 如果設置成功,代表是第一次請求,執行後續業務邏輯
- 如果設置失敗,代表已經執行過請求,直接返回
redis 是單線程的,所以不會有併發問題
3. 加鎖實現
具體流程如下:
- 客戶端請求服務端,對能代表這次請求的唯一標識加鎖,保證同一時刻同一請求只有一個能被執行
- 服務端根據唯一標識判斷是否第一次請求,比如查詢資料庫是否已存在該唯一標識的記錄,或者該唯一標識對應記錄狀態是否為【已完成】
- 如果是第一次請求,執行後續業務邏輯,否則直接返回
4. 冪等表
加鎖會影響性能,我們可以建一張冪等表,為能代表這次請求的唯一標識建立唯一約束
具體流程如下:
- 客戶端請求服務端,服務端會將本次請求的信息插入冪等表
- 因為有唯一約束,如果冪等表中不存在本次請求記錄,則插入成功,執行後續業務邏輯,插入失敗,則直接返回
使用這種方式,每次請求都會冪等表新建一條記錄,為了避免表數據過大,可以定期進行清理,或者使用流水錶來代替冪等表。使用插入而不是查詢,也能有效避免併發問題