1. 程式人生 > >再談冪等機制

再談冪等機制

要求 樂觀鎖 tran 接收 ads 消息推送 bottom mar http

一、什麽是冪等性?

冪等性(Idempotence)。在HTTP/1.1規範中冪等性的定義是:

Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

冪等性:就是用戶對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因為多次點擊而產生了副作用。

二、為什麽需要冪等

那麽我們為什麽需要接口具有冪等性呢?設想一下以下情形:

  • 在App中下訂單的時候,點擊確認之後,沒反應,就又點擊了幾次。在這種情況下,如果無法保證該接口的冪等性,那麽將會出現重復下單問題。

  • 在接收消息的時候,消息推送重復。如果處理消息的接口無法保證冪等,那麽重復消費消息產生的影響可能會非常大。

在分布式環境中,網絡環境更加復雜,因前端操作抖動、網絡故障、消息重復、響應速度慢等原因,對接口的重復調用概率會比集中式環境下更大,尤其是重復消息在分布式環境中很難避免。

三、如何保證接口的冪等性

接口的冪等性實際上就是接口可重復調用,在調用方多次調用的情況下,接口最終得到的結果是一致的。有些接口可以天然的實現冪等性,比如查詢接口,對於查詢來說,你查詢一次和兩次,對於系統來說,沒有任何影響,查出的結果也是一樣。

除了查詢功能具有天然的冪等性之外,增加、更新、刪除都要保證冪等性。那麽如何來保證冪等性呢?

3.1保證冪等策略

冪等需要通過唯一的業務單號來保證。也就是說相同的業務單號,認為是同一筆業務。使用這個唯一的業務單號來確保,後面多次的相同的業務單號的處理邏輯和執行效果是一致的。
下面以支付為例,在不考慮並發的情況下,實現冪等很簡單:①先查詢一下訂單是否已經支付過,②如果已經支付過,則返回支付成功;如果沒有支付,進行支付流程,修改訂單狀態為‘已支付’。

3.2防重復提交策略

上述的保證冪等方案是分成兩步的,第②步依賴第①步的查詢結果,無法保證原子性的。在高並發下就會出現下面的情況:第二次請求在第一次請求第②步訂單狀態還沒有修改為‘已支付狀態’的情況下到來。既然得出了這個結論,余下的問題也就變得簡單:把查詢和變更狀態操作加鎖,將並行操作改為串行操作。

列舉三種改進方式:

1、悲觀鎖,select for update,整個執行過程中鎖定該訂單對應的記錄。

2、樂觀鎖,affectrows = db.update(“update payorder set state=’已支付’ where orderid=$orderid and state=’未支付’ “),如果affectrows=1,執行充值,否則返回已處理。

3、定義防重復表,orderid為unique key或者primary key,執行前,先insert,若insert成功則執行充值,否則返回已處理

四、總結

業務層設計協議時,要求請求方定義不重復的業務流水號。應用實現時,利用數據庫樂觀鎖、插入unique key的日誌等方式保證並發時的冪等。

冪等性把關環節,在協議設計評審中,評審重要業務RPC或者http接口是否支持冪等,代碼評審中,重點把關請求並發時,是否仍舊能夠保證冪等性。設計人員和具體實現人員在實現過程中,也應該時刻自審冪等性的實現是否過關。

最後介紹一下美團點評開發GTI(它是一個輕量的重復操作關卡系統,它能夠確保在分布式環境中操作的唯一性。我們可以用它來間接保證每個操作的冪等性),感興趣可以去研究一下,技術分享圖片

技術分享圖片


再談冪等機制