再談冪等機制

1、什麼是冪等性?

冪等性(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.數據庫

冪等性:就是用戶對於同一操做發起的一次請求或者屢次請求的結果是一致的,不會由於屢次點擊而產生了反作用。網絡

2、爲何須要冪等

那麼咱們爲何須要接口具備冪等性呢?設想一下如下情形:併發

  • 在App中下訂單的時候,點擊確認以後,沒反應,就又點擊了幾回。在這種狀況下,若是沒法保證該接口的冪等性,那麼將會出現重複下單問題。
  • 在接收消息的時候,消息推送重複。若是處理消息的接口沒法保證冪等,那麼重複消費消息產生的影響可能會很是大。

在分佈式環境中,網絡環境更加複雜,因前端操做抖動、網絡故障、消息重複、響應速度慢等緣由,對接口的重複調用機率會比集中式環境下更大,尤爲是重複消息在分佈式環境中很難避免。分佈式

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

接口的冪等性實際上就是接口可重複調用,在調用方屢次調用的狀況下,接口最終獲得的結果是一致的。有些接口能夠自然的實現冪等性,好比查詢接口,對於查詢來講,你查詢一次和兩次,對於系統來講,沒有任何影響,查出的結果也是同樣。ide

除了查詢功能具備自然的冪等性以外,增長、更新、刪除都要保證冪等性。那麼如何來保證冪等性呢?高併發

3.1保證冪等策略

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

3.2防重複提交策略

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

列舉三種改進方式:
一、悲觀鎖,select for update,整個執行過程當中鎖定該訂單對應的記錄。
二、樂觀鎖,affectrows = db.update(「update payorder set state=’已支付’ where orderid=$orderid and state=’未支付’ 「),若是affectrows=1,執行充值,不然返回已處理。
三、定義防重複表,orderid爲unique key或者primary key,執行前,先insert,若insert成功則執行充值,不然返回已處理

4、總結

業務層設計協議時,要求請求方定義不重複的業務流水號。應用實現時,利用數據庫樂觀鎖、插入unique key的日誌等方式保證併發時的冪等。
冪等性把關環節,在協議設計評審中,評審重要業務RPC或者http接口是否支持冪等,代碼評審中,重點把關請求併發時,是否仍舊可以保證冪等性。設計人員和具體實現人員在實現過程當中,也應該時刻自審冪等性的實現是否過關。
最後介紹一下美團點評開發GTI(它是一個輕量的重複操做關卡系統,它可以確保在分佈式環境中操做的惟一性。咱們能夠用它來間接保證每一個操做的冪等性),感興趣能夠去研究一下, 20161008112749906

相關文章
相關標籤/搜索