冪等性問題和解決方法

2021-10-23 05:39:11 字數 2463 閱讀 8979

在實際的開發專案中,乙個對外暴露的介面往往會面臨很多次請求。這就需要考慮到乙個冪等性問題。

冪等性的概念是:任意多次執行所產生的影響均與一次執行的影響相同,即無論你請求了多少次,對資料庫的影響都只能有一次,不能重複處理。

所以,按照上面的理解,每次執行的結果都會發生變化,就是非冪等的。如下面三條sql,只有第三條是非冪等的。

select col1 from tab1 wher col2=

2,無論執行多少次都不會改變狀態,是天然的冪等。

update tab1 set col1=

1 where col2=

2,無論執行成功多少次狀態都是一致的,因此也是冪等操作。

update tab1 set col1=col1+

1 where col2=

2,每次執行的結果都會發生變化,這種不是冪等的。

這裡就可以牽扯到http請求了。http請求的get方法是冪等性的,因為不會對資料庫造成更改影響,每次返回的資料都一致。而post請求是非冪等的,因為每請求一次都會新增一條資料

(按restful規範,post常規是新增資料時使用。當然,也有例外,我們有的時候可能需要把查詢方法改造成 post 方法。比如,超長(1k)的 get url 使用 post 方法來替代,因為 get 受到 url 長度的限制。雖然,它不符合冪等性,但是它是一種折中的方案。)

因此 根據restful的規範,http的請求會有以下是否冪等性的判斷。

操作是否冪等

get獲取資料

√post

新建資料

×put

更新所有資料

√patch

更新部分資料

×delete

刪除資源

√冪等可以使得客戶端邏輯處理變得簡單,但是卻以服務邏輯變得複雜為代價。滿足冪等服務的需要在邏輯中至少包含兩點:

首先去查詢上一次的執行狀態,如果沒有則認為是第一次請求

在服務改變狀態的業務邏輯前,保證防重複提交的邏輯

冪等是為了簡化客戶端邏輯處理,卻增加了服務提供者的邏輯和成本,是否有必要,需要根據具體場景具體分析,因此除了業務上的特殊要求外,盡量不提供冪等的介面。

增加了額外控制冪等的業務邏輯,複雜化了業務功能;

把並行執行的功能改為序列執行,降低了執行效率。

防重表

資料庫建立唯一性索引,可以保證最終插入資料庫的只有一條資料(比如訂單表對訂單號進行唯一索引,所有重複提交可能產生同乙個訂單號的都會被拆除。當然,訂單號要按你自己的設定走,一般訂單號設計會是時間戳加迭代。那麼如果是這樣,建立仍然不能保證冪等,具體根據業務需求來判定建立的唯一索引位置)

token令牌機制,

分為兩個階段,獲取token和使用token。每次介面請求前先獲取乙個token,然後再下次請求的時候在請求的header體中加上這個token,後台進行驗證,如果驗證通過刪除token,下次請求再次判斷token。如果使用上redis快取,流程圖會是這樣。

先查詢後判斷,

首先通過查詢資料庫是否存在資料,如果存在證明已經請求過了,直接拒絕該請求,如果沒有存在,就證明是第一次進來,直接放行。

支付緩衝區

把訂單的支付請求都快速地接下來,乙個快速接單的緩衝管道。後續使用非同步任務處理管道中的資料,過濾掉重複的待支付訂單。優點是同步轉非同步,高吞吐。不足是不能及時地返回支付結果,需要後續監聽支付結果的非同步返回。(一般支付都是採用這種方式)

悲觀鎖或者樂觀鎖。

悲觀鎖可以保證每次for update的時候其他sql無法update資料(在資料庫引擎是innodb的時候,select的條件必須是唯一索引,防止鎖全表)

樂觀鎖,一般通過version來做樂觀鎖,這樣既能保證執行效率,又能保證冪等。例如: update tab1 set col1=1,version=version+1 where version=#version# 不過,樂觀鎖存在失效的情況,就是常說的aba問題,不過如果version版本一直是自增的就不會出現aba的情況。(aba可以檢視這篇文章鏈結,關於cas機制可以看這篇鏈結)

分布式鎖

防重表可以使用分布式鎖代替,比如redis。訂單發起支付請求,支付系統會去redis快取中查詢是否存在該訂單號的key,如果不存在,則向redis增加key為訂單號。查詢訂單支付已經支付,如果沒有則進行支付,支付完成後刪除該訂單號的key。通過redis做到了分布式鎖,只有這次訂單訂單支付請求完成,下次請求才能進來。相比去重表,將放併發做到了快取中,較為高效。思路相同,同一時間只能完成一次支付請求。

RocketMQ解決冪等性問題

一.造成重複消費的原因 在於回饋機制。正常情況下,消費者在消費訊息時候,消費完畢後,會傳送乙個ack確認資訊給訊息佇列 broker 訊息佇列 broker 就知道該訊息被消費了,就會將該訊息從訊息佇列中刪除。不同的訊息佇列傳送的確認資訊形式不同,例如rabbitmq是傳送乙個ack確認訊息,roc...

前端問題和解決方法

centering text in column th.dt center,td.dt center change table header color using bootstrap thead th tbody td change select default color selection m...

MQ的冪等性問題

冪等性問題 1 生產者已把訊息傳送到mq,在mq給生產者返回ack的時候網路中斷,故生產者未收到確定資訊,生產者認為訊息未傳送成功,但實際情況是,mq已成功接收到了訊息,在網路重連後,生產者會重新傳送剛才的訊息,造成mq接收了重複的訊息 2 消費者在消費mq中的訊息時,mq已把訊息傳送給消費者,消費...