如何讓訂單服務具備冪等性?

2021-10-24 11:10:03 字數 1133 閱讀 5923

先解釋下什麼叫冪等性:

原本是數學上的概念,即使公式:f(x)=f(f(x)) 能夠成立的數學性質。用在程式設計領域,則意為對同乙個系統,使用同樣的條件,一次請求和重複的多次請求對系統資源的影響是一致的。

1.乙個冪等的建立訂單服務,無論建立訂單的請求傳送多少次,正確的結果是,資料庫只有一條新建立的訂單記錄。

這裡面就出現了乙個不好解決的問題:訂單服務怎麼知道,發來的建立訂單的請求是重複的呢?

在插入資料庫之前,先查詢資料庫是否存在重複訂單,行不行?不太行,因為很難用sql的條件定義「重複的訂單」,訂單使用者一樣、訂單商品一樣、訂單**一樣,就認定為重複訂單?不一定,若使用者就是連續下了2個重複的訂單呢,所以這個方式說起來容易,實際上很難實現。

很多電商採用的是思路是,利用資料庫表主鍵唯一約束特性,在插入資料時帶上主鍵,如果重複插入多次,就會失敗,這就能保證訂單服務的冪等性了。

具體做法是:

給訂單系統增加個「生成訂單號」的系統,在使用者建立訂單前先去生成訂單號,在使用者提交訂單的時候,在建立訂單的請求中帶上這個訂單號。

需要注意乙個實際問題:如果資料庫是因為重複訂單號導致插入訂單失敗,訂單服務不要把錯誤資訊返回給前端,否則就會出現這樣的問題:使用者建立訂單,頁面提示建立失敗,而實際上訂單卻建立成功了。正確的做法是,遇到這種情況,訂單服務直接返回建立成功。

2.如何解決aba的問題?

各種更新訂單的服務一樣也要具有冪等性。比如支付、發貨等過程,都需要對訂單狀態做update操作,在高併發情況下,就會出現aba的問題。

那什麼是aba問題?比如有甲乙2個請求,乙個是將訂單狀態更新為a,另乙個是更新為b,這是正常情況。那在高併發下可能出現:訂單狀態在更新為a後,沒來得及把響應告訴甲,另一請求又更新成了b,由於甲沒收到響應,(重試機制)又發起了請求,又把b更新成了a,這個就是aba問題,那怎麼解決呢?

我們可以給訂單表新增一列:version版本號來限制,每次update時,同時將version自增1,在update時,帶上條件version,這樣就可以把每次請求做版本區分,來達到解決aba問題,如下sql:

update table set status=b,version=version+1 where id=1 and version=3

每次查詢時,都將version返回給前端,進行修改時,需要再將version放到更新請求引數中。

訂單防重(冪等性)

冪等性需要唯一的業務訂單號來保證,插入類介面 1.先select後insert 再引數校驗是否支付過 在執行支付 缺點 1多一次select,高併發下效能低 2.由於是兩個操作,不具備原子性,存在事務問題,需要加 transaction 2.樂觀鎖 只適合update類介面 sql如下update ...

如何保證微服務介面的冪等性

在微服務架構下,我們在完成乙個訂單流程時經常遇到下面的場景 乙個訂單建立介面,第一次呼叫超時了,然後呼叫方重試了一次 在訂單建立時,我們需要去扣減庫存,這時介面發生了超時,呼叫方重試了一次 當這筆訂單開始支付,在支付請求發出之後,在服務端發生了扣錢操作,介面響應超時了,呼叫方重試了一次 乙個訂單狀態...

服務高可用 冪等性設計

什麼是冪等性?一般在服務呼叫時,讀服務如果呼叫失敗了,會自動按配置次數轉移到別的服務上去請求。而寫服務就不能重複請求,如果因為超時或者網路故障等原因被呼叫服務並沒有返回成功的響應,服務呼叫方就認為是失敗了,但很有可能的是已經成功了,如果繼續重複請求寫服務,如轉賬類的服務,可能會造成嚴重的後果。所以,...