基於Redis&MySQL接口冪等性設計
欲把相思說似誰,淺情人不知。
1、冪等
冪等性即多次調用接口或方法不會改變業務狀態,可以保證重復調用的結果和單次調用的結果一致。
2、冪等使用場景
前端重復提交
用戶注冊、創建商品、提交訂單、轉賬、支付等操作,前端都會提交一些數據給后台服務,后台需要根據用戶提交的數據在數據庫中創建記錄。如果用戶不小心多點了幾次,后端收到了好幾次提交,這時就會在數據庫中重復創建了多條記錄。這就是接口沒有冪等性帶來的bug。
接口超時重試
對於給第三方調用的接口,有可能會因為網絡原因而調用失敗,這種情況一般在設計的時候會對接口調用加上失敗重試的機制,如果第一次調用已經執行了一半時發生了網絡異常,這時再次調用時就會因為臟數據的存在而出現調用異常。
消息重復消費
在使用消息中間件來處理消息隊列,且手動 ack 確認消息被正常消費時。如果消費者突然斷開連接,那么已經執行了一半的消息會重新放回隊列。
當消息被其他消費者重新消費時,如果沒有冪等性,就會導致消息重復消費引起結果異常如數據庫重復數據等。
3、解決方案
基於Token
通過token 機制實現接口的冪等性,是一種比較通用性的實現方法。
具體流程步驟:
-
客戶端會先發送一個請求去獲取 token,服務端會生成一個全局唯一的 ID 作為 token 保存在 redis 中,同時把這個 ID 返回給客戶端;
-
客戶端第二次調用業務請求的時候必須攜帶這個 token;
-
服務端會校驗這個 token,如果校驗成功,則執行業務,並刪除 redis 中的 token;
-
如果校驗失敗,說明 redis 中已經沒有對應的 token,則表示重復操作,直接返回指定的結果給客戶端。
基於MySQL
基於MySQL實現方式是利用了 mysql 唯一索引的特性。
具體流程步驟:
-
建立一張去重表,其中某個字段需要建立唯一索引,如訂單ID,用戶ID;
-
客戶端去請求服務端,服務端會將這次請求的一些信息插入這張去重表中;
-
因為表中某個字段帶有唯一索引,如果插入成功,證明表中沒有這次請求的信息,則執行后續的業務邏輯;
-
如果插入失敗,則代表已經執行過當前請求,直接返回。
基於Redis
基於Redis是利用了 SETNX 命令實現的。
SETNX key value:將 key 的值設為 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 SETNX 不做任何動作。
該命令在設置成功時返回 1,設置失敗時返回 0。
具體流程步驟:
-
客戶端先請求服務端,會拿到一個能代表這次請求業務的唯一字段;
-
將該字段以 SETNX 的方式存入 redis 中,並根據業務設置相應的超時時間;
-
如果設置成功,證明這是第一次請求,則執行后續的業務邏輯;
-
如果設置失敗,則代表已經執行過當前請求,直接返回。
欲把相思說似誰
淺情人不知