防重復請求處理方案

1. 背景

在業(yè)務開發(fā)中,我們常會面對防止重復請求的問題。當服務端對于請求的響應涉及數(shù)據(jù)的修改,或狀態(tài)的變更時,可能會造成極大的危害。重復請求的后果在交易系統(tǒng)、售后維權(quán),以及支付系統(tǒng)中尤其嚴重。
前臺操作的抖動,快速操作,網(wǎng)絡通信或者后端響應慢,都會增加后端重復處理的概率。
前臺操作去抖動和防快速操作的措施,我們首先會想到在前端做一層控制。當前端觸發(fā)操作時,或彈出確認界面,或disable入口并倒計時等等。

2. 問題

雖然前端的限制僅能解決少部分問題,且不夠徹底,后端自有的防重復處理措施必不可少,義不容辭。
在接口實現(xiàn)中,我們常要求接口要滿足冪等性,來保證多次重復請求時只有一次有效。
查詢類的接口幾乎總是冪等的,但在包含諸如數(shù)據(jù)插入,多模塊數(shù)據(jù)更新時,達到冪等性會比較難,尤其是高并發(fā)時的冪等性要求。比如第三方支付前臺回調(diào)和后臺回調(diào),第三方支付批量回調(diào),慢性能業(yè)務邏輯(如用戶提交退款申請,商家同意退貨/退款等)或慢網(wǎng)絡環(huán)境時,是重復處理的高發(fā)場景。

3. 方案

3.1 利用唯一索引機制的驗證

需要原子性操作,想到了數(shù)據(jù)庫的唯一索引。
新建一個TradeLock表:

CREATE TABLE `TradeLock` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL COMMENT '鎖類型',
`lockId` int(11) NOT NULL DEFAULT '0' COMMENT '業(yè)務ID',
`status` int(11) NOT NULL DEFAULT '0' COMMENT '鎖狀態(tài)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Trade鎖機制';

每次request進來則往表里面插入數(shù)據(jù):

——成功,則可以繼續(xù)操作(相當于獲取鎖);
——失敗,則說明有操作在進行。

操作完成后,刪除此條記錄。(相當于釋放鎖)


利用唯一索引

3.2 基于緩存的計數(shù)器驗證

由于數(shù)據(jù)庫的操作比較消耗性能,了解到redis的計數(shù)器也是原子性操作。果斷采用計數(shù)器。既可以提高性能,還不用存儲,而且能提升qps的峰值。
以操作訂單為例子:
每次request進來則新建一個以orderId為key的計數(shù)器,然后+1。

如果>1(不能獲得鎖): 說明有操作在進行,刪除。
如果=1(獲得鎖): 可以操作。

操作結(jié)束(刪除鎖):刪除這個計數(shù)器。


基于緩存的計數(shù)器驗證

4. 總結(jié)

接口的防重復方案很多,但是出現(xiàn)的情況也很多。所以必須每個細節(jié)都做好把控,從前端到后端,每個節(jié)點都要到位,一定要符合接口的冪等性原則。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容