【轉載】分散式系統中的冪等性
我們的系統大多拆分為分散式SOA,或者微服務,一套系統中包含了多個子系統服務,而一個子系統服務往往會去呼叫另一個服務,而服務呼叫服務無非就是使用RPC通訊或者restful,既然是通訊,那麼就有可能再伺服器處理完畢後返回結果的時候掛掉,這個時候使用者端發現很久沒有反應,那麼就會多次點選按鈕,這樣請求有多次,那麼處理資料的結果是否要統一呢?那是肯定的!尤其再支付場景。
冪等性:就是使用者對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因為多次點選而產生了副作用。舉個最簡單的例子,那就是支付,使用者購買商品後支付,支付扣款成功,但是返回結果的時候網路異常,此時錢已經扣了,使用者再次點選按鈕,此時會進行第二次扣款,返回結果成功,使用者查詢餘額發現多扣錢了,流水記錄也變成了兩條...
在以前的單應用系統中,我們只需要把資料操作放入事務中即可,發生錯誤立即回滾,但是再響應客戶端的時候也有可能出現網路中斷或者異常等等。
在增刪改查4個操作中,尤為注意就是增加或者修改,
查詢對於結果是不會有改變的,
刪除只會進行一次,使用者多次點選產生的結果一樣
修改在大多場景下結果一樣
增加在重複提交的場景下會出現
那麼如何設計接口才能做到冪等呢?
方法一、單次支付請求,也就是直接支付了,不需要額外的資料庫操作了,這個時候發起非同步請求建立一個唯一的ticketId,就是門票,這張門票只能使用一次就作廢,具體步驟如下:
-
非同步請求獲取門票
-
呼叫支付,傳入門票
-
根據門票ID查詢此次操作是否存在,如果存在則表示該操作已經執行過,直接返回結果;如果不存在,支付扣款,儲存結果
-
返回結果到客戶端
如果步驟4通訊失敗,使用者再次發起請求,那麼最終結果還是一樣的.
方法二、分散式環境下各個服務相互呼叫
這邊就要舉例我們的系統了,我們支付的時候先要扣款,然後更新訂單,這個地方就涉及到了訂單服務以及支付服務了。
使用者呼叫支付,扣款成功後,更新對應訂單狀態,然後再儲存流水。
而在這個地方就沒必要使用門票ticketId了,因為會比較閒的麻煩
(支付狀態:未支付,已支付)
步驟:
1、查詢訂單支付狀態
2、如果已經支付,直接返回結果
3、如果未支付,則支付扣款並且儲存流水
4、返回支付結果
如果步驟4通訊失敗,使用者再次發起請求,那麼最終結果還是一樣的
對於做過支付的朋友,冪等,也可以稱之為衝正,保證客戶端與服務端的交易一致性,避免多次扣款。