面試官扎心一問:防止重複請求提交,有什麼方案?

背景

在日常開發中,咱們常常會面對防止重複請求的問題。當服務端對於請求的響應涉及數據的修改,或狀態的變動時,可能會形成極大的危害。重複請求的後果在交易系統、售後維權,以及支付系統中尤爲嚴重。可是不少時候,都是期望着前端來限制,好比提交以後,按鈕diseabled之類的,其實這些都是不靠譜的。關鍵時候仍是須要後端來校驗。前端

解決方式

一、基於緩存數據狀態的驗證

Redis存儲查詢輕量快速。在request進來的時候,能夠先記錄在緩存中。後續進來的request每次進行驗證。整個流程處理完成,清除緩存。redis

  if (!CacheExtension.getInstance().AddUnique($"{key}_unique", 1, DateTimeOffset.Now.AddDays(365)))
            {
                LogExtention.getInstance().WriteCustomLogAsync("", "", true, "上批次還未執行結束");
                return ResponseResult.FromError("上批次還未執行結束!");
            }
 if (!string.IsNullOrEmpty(uniqueKey))
            {
                CacheExtension.getInstance().Remove(uniqueKey);
            }
            return ResponseResult.Ok();

 

二、利用惟一索引機制的驗證

須要原子性操做,想到了數據庫的惟一索引。新建一個表,每次request進來則往表裏面插入數據, 操做完成後,刪除此條記錄。shell

 

 

 

三、基於緩存的計數器驗證

因爲數據庫的操做比較消耗性能,瞭解到redis的計數器也是原子性操做。果斷採用計數器。既能夠提升性能,還不用存儲,並且能提高qps的峯值。 每次request進來則新建一個以orderId爲key的計數器,而後+1。若是>1(不能得到鎖): 說明有操做在進行,刪除。若是=1(得到鎖): 能夠操做。數據庫

redis> SET test 20
OK
redis> INCR test
(integer) 21
redis> GET test # 數字值在 Redis 中以字符串的形式保存
"21"

//獲取指定的全部計數器
HGETALL counter:user:{userID}   

//獲取指定的指定計數器
HMGET counter:user:{userID}  praiseCnt hostCnt 

//指定點贊數+1
HINCRBY counter:user:{userID}   praiseCnt

 


總結

一、c#自己有lock機制,單體模式能夠使用。

二、可是考慮到咱們的分佈式部署,建議仍是用緩存。在大併發的狀況下,程序各類狀況的發生。特別是涉及到金額操做。因此在大併發要互斥的狀況下能夠考慮二、3兩種方案。

相關文章
相關標籤/搜索