亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

數據一致性

前面總結了微服務的9個痛點,有些痛點沒有好的解決方案,而有些痛點是有對策的,從本章開始,就來講解某些痛點對應的解決方案。

這一章先解決數據一致性的問題,先來看一個實際的業務場景。

業務場景:下游服務失敗后上游服務如何獨善其身

前面講過,使用微服務時,很多時候需要跨多個服務去更新多個數據庫的數據,架構如圖13-1所示。

• 圖13-1 微服務上下游示意圖

如圖13-1所示,如果業務正常運轉,3個服務的數據應該分別變為a2、b2、c2,此時數據才一致。但是如果出現網絡抖動、服務超負荷或者數據庫超負荷等情況,整個處理鏈條有可能在步驟2失敗,這時數據就會變成a2、b1、c1;當然也有可能在步驟3失敗,最終數據就會變成a2、b2、c1。這樣數據就出錯了,即數據不一致。

在本章所討論的項目開始之前,因為之前的改造項目時間很緊,所以開發人員完全沒有精力處理系統數據一致性的問題,最終業務系統出現了很多錯誤數據,業務部門發工單告知IT部門數據有問題,經過一番檢查后,IT部門發現是因為分布式更新的原因導致了數據不一致。

此時,IT部門不得不抽出時間針對數據一致性問題給出一個可靠的解決方案。通過討論,IT部門把數據一致性的問題歸類為以下兩種情況。

1.實時數據不一致可以接受,但要保證數據的最終一致性

因為一些服務出現錯誤,導致圖13-1中的步驟3失敗,此時處理完請求后,數據就變成了a2、b2、c1,不過沒關系,只需保證最終數據是a2、b2、c2即可。

在以往的一個項目中,業務場景是這樣的(示例有所簡化):零售下單時,一般需要實現在商品服務中扣除商品的庫存、在訂單服務中生成一個訂單、在交易服務中生成一個交易單這3個步驟。假設交易單生成失敗,就會出現庫存扣除、訂單生成,但交易單沒有生成的情況,此時只需保證最終交易單成功生成即可,這就是最終一致性。

2.必須保證實時一致性

如果圖13-1中的步驟2和步驟3成功了,數據就會變成b2、c2,但是如果步驟3失敗,那么步驟1和步驟2會立即回滾,保證數據變回a1、b1。

在以往的一個項目中,業務場景類似這樣:用戶使用積分兌換折扣券時,需要實現扣除用戶積分、生成一張折扣券給用戶這兩個步驟。如果還是使用最終一致性方案的話,有可能出現用戶積分扣除而折扣券還未生成的情況,此時用戶進入賬戶發現積分沒有了,也沒有折扣券,就會馬上投訴。

那怎么辦呢?直接將前面的步驟回滾,并告知用戶處理失敗請繼續重試即可,這就是實時一致性。

針對以上兩種情況,具體解決方案是什么呢?下面一起來看看。

最終一致性方案

對于數據要求最終一致性的場景,實現思路是這樣的。

1)每個步驟完成后,生產一條消息給MQ,告知下一步處理接下來的數據。

2)消費者收到這條消息,將數據處理完成后,與步驟1)一樣觸發下一步。

3)消費者收到這條消息后,如果數據處理失敗,這條消息應該保留,直到消費者下次重試。

將3個服務的整個調用流程走下來,邏輯還是比較復雜的,整體流程如圖13-2所示。

• 圖13-2 服務調用流程

詳細的實現邏輯如下。

1)調用端調用Service A。

2)Service A將數據庫中的a1改為a2。

3)Service A生成一條步驟2(暫且命名為Step2)的消息給MQ。

4)Service A返回成功信息給調用端。

5)Service B監聽Step2的消息,獲得一條消息。

6)Service B將數據庫中的b1改為b2。

7)Service B生成一條步驟3(暫且命名為Step3)的消息給MQ。

8)Service B將Step2的消息設置為已消費。

9)Service C監聽Step3的消息,獲得一條消息。

10)Service C將數據庫中的c1改為c2。

11)Service C將Step3的消息設置為已消費。

接下來要考慮,如果每個步驟失敗了該怎么辦?

1)調用端調用Service A。

解決方案:直接返回失敗信息給用戶,用戶數據不受影響。

2)Service A將數據庫中的a1改為a2。

解決方案:如果這一步失敗,就利用本地事務數據直接回滾,用戶數據不受影響。

3)Service A生成一條步驟2)(Step2)的消息給MQ。

解決方案:如果這一步失敗,就利用本地事務數據將步驟2)直接回滾,用戶數據不受影響。

4)Service A返回成功信息給調用端。

解決方案:不用處理。

5)Service B監聽Step2的消息,獲得一條消息。

解決方案:如果這一步失敗,MQ有對應機制,無須擔心。

6)Service B將數據庫中的b1改為b2。

解決方案:如果這一步失敗,則利用本地事務直接將數據回滾,再利用消息重試的特性重新回到步驟5)。

7)Service B生成一條步驟3)(Step3)的消息給MQ。

解決方案:如果這一步失敗,MQ有生產消息失敗重試機制。若出現極端情況,服務器會直接崩潰,因為Step2的消息還沒有消費,MQ會有重試機制,然后找另一個消費者重新從步驟5)執行。

8)Service B將Step2的消息設置為已消費。

解決方案:如果這一步失敗,MQ會有重試機制,找另一個消費者重新從步驟5)執行。

9)Service C監聽Step3的消息,獲得一條消息。

解決方案:參考步驟5)的解決方案。

10)Service C將數據庫中的c1改為c2。

解決方案:參考步驟6)的解決方案。

11)Service C將Step3的消息設置為已消費。

解決方案:參考步驟8)的解決方案。

以上就是最終一致性的解決方案,這個方案還有兩個問題。

1)因為利用了MQ的重試機制,所以有可能出現步驟6)和步驟10)重復執行的情況,此時該怎么辦?比如,上面流程中的步驟8)如果失敗了,就會從步驟5)重新執行,這時就會出現步驟6)執行兩遍的情況。為此,在下游(步驟6)和步驟10))更新數據時,需要保證業務代碼的冪等性(關于冪等性,在第1章提過)。

2)如果每個業務流程都需要這樣處理,豈不是需要額外寫很多代碼?那是否可以將類似流程的重復代碼抽取出來?答案是可以,這里使用的MQ相關邏輯在其他業務流程中也通用,這個項目最終就是將這些代碼抽取出來并進行了封裝。因為重復代碼抽取的方法比較簡單,這里就不展開了。

實時一致性方案

實時一致性其實就是常說的分布式事務。

MySQL其實有一個兩階段提交的分布式事務方案MySQL XA,但是該方案存在嚴重的性能問題。比如,一個數據庫的事務與多個數據庫間的XA事務性能可能相差10倍。另外,XA的事務處理過程會長期占用鎖資源,所以項目組一開始就沒有考慮這個方案。

而當時比較流行的方案是使用TCC模式,下面簡單介紹一下。

TCC模式

在TCC模式中,會把原來的一個接口分為Try接口、Confirm接口、Cancel接口。

1)Try接口:用來檢查數據、預留業務資源。

2)Confirm接口:用來確認實際業務操作、更新業務資源。

3)Cancel接口:是指釋放Try接口中預留的資源。

比如在積分兌換折扣券的例子中,需要調用賬戶服務減積分(步驟1)、營銷服務加折扣券(步驟2)這兩個服務,那么針對賬戶服務減積分這個接口,需要寫3個方法,代碼如下所示。


 

同樣,針對營銷服務加折扣券這個接口,也需要寫3個方法,而后調用的大體步驟如圖13-3所示。

• 圖13-3 賬戶和營銷服務TCC處理流程

圖13-3中,除Cancel步驟以外的步驟,代表成功的調用路徑,如果中間出錯,則去調用相關服務的回退(Rollback)方法進行手工回退。該方案原來只需要在每個服務中寫一段業務代碼,而現在需要分成3段來寫,而且還涉及一些注意事項。

1)需要保證每個服務的Try方法執行成功后,Confirm方法在業務邏輯上能夠執行成功。

2)可能會出現Try方法執行失敗而Cancel被觸發的情況,此時需要保證正確回滾。

3)可能因為網絡擁堵而出現Try方法調用被堵塞的情況,此時事務控制器判斷Try失敗并觸發了Cancel方法,之后Try方法的調用請求到了服務這里,應該拒絕Try請求邏輯。

4)所有的Try、Confirm、Cancel都需要確保冪等性。

5)整個事務期間的數據庫數據處于一個臨時的狀態,其他請求需要訪問這些數據時,需要考慮如何正確被其他請求使用,而這種使用包括讀取和并發的修改。

所以,TCC模式是一個實施起來很麻煩的方案,除了每個業務代碼的工作量乘3之外,還需要通過相應邏輯應對上面的注意事項,這樣出錯的概率就太高了。

后來,筆者在一篇介紹Seata的文章中了解到AT模式也能解決這個問題。

Seata中AT模式的自動回滾

自動回滾對于使用Seata的人來說操作比較簡單,只需要在觸發整個事務的業務發起方的方法中加入@GlobalTransactional標注,并且使用普通的@Transactional包裝好分布式事務中相關服務的相關方法即可。

對于Seata的內在機制,AT模式的自動回滾往往需要執行以下步驟(分為3個階段)。

階段1

1)解析每個服務方法執行的SQL,記錄SQL的類型(Update、Insert或Delete),修改表并更新SQL條件等信息。

2)根據前面的條件信息生成查詢語句,并記錄修改前的數據鏡像。

3)執行業務的SQL。4)記錄修改后的數據鏡像。

5)插入回滾日志:把前后鏡像數據及業務SQL相關的信息組成一條回滾日志記錄,插入UNDOLOG表中。

6)提交前,向TC注冊分支,并申請相關修改數據行的全局鎖。

7)本地事務提交:業務數據的更新與前面步驟生成的UNDOLOG一并提交。

8)將本地事務提交的結果上報給事務控制器。

階段2

收到事務控制器的分支回滾請求后,開啟一個本地事務,執行如下操作。

1)查找相應的UNDOLOG記錄。

2)數據校驗:將UNDOLOG中的后鏡像數據與當前數據進行對比,如果存在不同,說明數據被當前全局事務之外的動作做了修改,此時需要根據配置策略進行處理。

3)根據UNDOLOG中的前鏡像數據和業務SQL的相關信息生成回滾語句并執行。

4)提交本地事務,并把本地事務的執行結果(即分支事務回滾的結果)上報事務控制器。

階段3

1)收到事務控制器的分支提交請求后,將請求放入一個異步任務隊列

中,并馬上返回提交成功的結果給事務控制器。

2)異步任務階段的分支提交請求將異步、批量地刪除相應的UNDOLOG記錄。

以上就是Seata AT模式的簡單介紹。

嘗試Seata

當時,雖然Seata還沒有更新到1.0,且官方也不推薦線上使用,但是項目組最終還是使用了它,原因如下。

1)因為實時一致性的場景很少,而且發生頻率低,所以并不會大規模使用,影響面在可控范圍內。如果實時一致性的場景發生頻率高,并發量就高,業務人員對性能的要求也高,此時就會與業務溝通,采用最終一致性的方案。

2)Seata AT模式與TCC模式相比,只有增加一個@GlobalTransactional的工作量,因此兩者的工作量相差很多,也就是說,對項目組來說,投入產出比更高,值得冒險。這可能也是Seata發展很快的原因之一。

雖然Seata AT模式有些小缺陷,但是瑕不掩瑜。

小結

最終一致性與實時一致性的解決方案設計完成后,不僅沒有給業務開發人員帶來額外工作量,也沒有影響業務項目進度的日常推進,還大大減少了數據不一致的出現概率,因此數據不一致的痛點得到了較大緩解。

分享到:
標簽:微服
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定