1. 程式人生 > >分散式系統的冪等性設計

分散式系統的冪等性設計

WEB資源或API方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。
冪等性是系統的介面對外一種承諾(而不是實現), 承諾只要呼叫介面成功, 外部多次呼叫對系統的影響是一致的。
冪等性是分散式系統設計中的一個重要概念,對超時處理、系統恢復等具有重要意義。宣告為冪等的介面會認為外部呼叫失敗是常態, 並且失敗之後必然會有重試。例如,在因網路中斷等原因導致請求方未能收到請求返回值的情況下,如果該資源具備冪等性,請求方只需要重新請求即可,而無需擔心重複呼叫會產生錯誤。實際上,我們常用的HTTP協議的方法是具有冪等性語義要求的,比如:get方法用於獲取資源,不應有副作用,因此是冪等的;post方法用於建立資源,每次請求都會產生新的資源,因此不具備冪等性;put方法用於更新資源,是冪等的;delete方法用於刪除資源,也是冪等的。

常見用來保證冪等的手段:

1.MVCC方案
多版本併發控制,該策略主要使用update with condition(更新帶條件來防止)來保證多次外部請求呼叫對系統的影響是一致的。在系統設計的過程中,合理的使用樂觀鎖,通過version或者updateTime(timestamp)等其他條件,來做樂觀鎖的判斷條件,這樣保證更新操作即使在併發的情況下,也不會有太大的問題。例如

select * from tablename where condition=#condition# //取出要跟新的物件,帶有版本versoin
update tableName set name=#name#,version=version+1 where version=#version#

在更新的過程中利用version來防止,其他操作對物件的併發更新,導致更新丟失。為了避免失敗,通常需要一定的重試機制。

2.去重表
在插入資料的時候,插入去重表,利用資料庫的唯一索引特性,保證唯一的邏輯。

3.悲觀鎖
select for update,整個執行過程中鎖定該訂單對應的記錄。注意:這種在DB讀大於寫的情況下儘量少用。

4.select + insert
併發不高的後臺系統,或者一些任務JOB,為了支援冪等,支援重複執行,簡單的處理方法是,先查詢下一些關鍵資料,判斷是否已經執行過,在進行業務處理,就可以了。注意:核心高併發流程不要用這種方法。

5.狀態機冪等
在設計單據相關的業務,或者是任務相關的業務,肯定會涉及到狀態機,就是業務單據上面有個狀態,狀態在不同的情況下會發生變更,一般情況下存在有限狀態機,這時候,如果狀態機已經處於下一個狀態,這時候來了一個上一個狀態的變更,理論上是不能夠變更的,這樣的話,保證了有限狀態機的冪等。

6.token機制,防止頁面重複提交

  • 業務要求:頁面的資料只能被點選提交一次
  • 發生原因:由於重複點選或者網路重發,或者nginx重發等情況會導致資料被重複提交
  • 解決辦法:

    叢集環境:採用token加redis(redis單執行緒的,處理需要排隊)
    單JVM環境:採用token加redis或token加jvm記憶體

  • 處理流程:

    資料提交前要向服務的申請token,token放到redis或jvm記憶體,token有效時間
    提交後後臺校驗token,同時刪除token,生成新的token返回

  • token特點:要申請,一次有效性,可以限流

7.對外提供介面的api如何保證冪等
如銀聯提供的付款介面:需要接入商戶提交付款請求時附帶:source來源,seq序列號。
source+seq在資料庫裡面做唯一索引,防止多次付款(併發時,只能處理一個請求)

總結: 冪等性應該是合格程式設計師的一個基因,在設計系統時,是首要考慮的問題,尤其是在像支付寶,銀行,網際網路金融公司等涉及的都是錢的系統,既要高效,資料也要準確,所以不能出現多扣款,多打款等問題,這樣會很難處理,使用者體驗也不好 。