1. 程式人生 > >分散式系統最終一致性的防護欄---冪等

分散式系統最終一致性的防護欄---冪等

實踐證明,在分散式系統,同時滿足CAP定律(一致性、可用性、分割槽容錯性)是不太可能的。雖然強一致性可以提高使用者的體驗,但是犧牲了系統的可用性,在經過綜合的考慮和驗證下,業界普遍的做法是在一致性和可用性進行了平衡,也就是提高系統的可用性,保證系統的最終一致性。而系統的冪等就是保證系統由強一致性轉換為最終一致性的防護欄。

冪等是何許東西,舉例說明。

假設應用系統是一個交易系統,此係統提供了取現的業務withdraw(account_id,amount)函式,如下圖所示


正常流程應該是,客戶端發起提現請求1,系統收到請求後把對應賬戶的餘額減去提現額度,然後返回success給客戶端2,客戶端收到系統的響應後,提現完成。

但是,由於網路或者其他原因導致2斷掉,即系統的響應沒有到client。client沒有收到響應,就會重複請求3(重新整理等),系統收到client提現請求,又會做一次總額減少的操作,然後完成之後,響應success給客戶端4,在這種情況下,本來使用者提取100,結果賬戶餘額減少了200,不是使用者想看到的,使用者體驗差。為了消除這種問題,就要對提現這個功能做冪等。

什麼是冪等,冪等就是對方法多次操作的結果和一次操作的結果是一致的。

對於上述提現系統的冪等的一種實現方法如下:

每次提現client都會帶著一個id,server後端接到請求後會通過id來判斷,是不是已經操作。如下圖


如上圖所示,client在每次提現之前都會去伺服器拿一次ticket,拿到ticket之後,然後帶著ticket去請求提現功能,server收到提現請求後,首先會check客戶端傳過來的ticket,判斷是不是重複請求。這樣就能解決重複提交的問題。

正常流程應該是1->2->5->6,中間環節出現任何問題,都不會發生重複請求,例如,假如2沒有到達client,6沒有到達client。假設2沒有到達,使用者會重複傳送請求3,得到一個新的ticket不影響整個流程的業務。如果6沒有到達client,client重複7傳送到server,server拿到ticket,判斷此請求已經處理,不在處理這次請求,響應client,達到使用者正確的提現行為。

下面就說一下怎麼達到最終一致性,還是舉例子來說明

一個交易系統,使用者購買產品,會產生兩個操作,使用者餘額減少和增加交易記錄,假設使用者餘額表和交易記錄表是分庫儲存的,所以會產生兩個事務,最終一致性就是保證這兩個事務最終一致。

具體實踐,如下:

一種常見的做法就是在第一個事務中通過本地事務的事務保證,保證"增加交易記錄"和“增加一條非同步訊息佇列記錄”同時成功或者同時失敗,增加一張updates_applied表,此表記錄已經處理過的訊息,第二個事務,讀出訊息佇列的訊息(不刪除),通過判斷updates_applied表,來判斷此訊息是不是已經執行,如果沒有執行,則執行相關業務邏輯(保證冪等性),執行完此訊息後,在updates_applied增加一條操作記錄,事務結束。用事務保證非同步訊息的執行和增加updates_applied的記錄的一致性操作,然後刪除佇列。

在實踐中,可以靈活運用