分佈式系統一致性問題解決實戰

1、背景及問題描述

業務背景web

      商戶提交表單數據至旺鋪(deco項目,如下皆稱爲deco),deco須要接入poi系統進行裝修內容的人工審覈,詳細流程見下圖。sql

問題

      店鋪裝修審覈狀態在deco系統和poi系統之間不一致,下圖中1,2,3步提交流程會出現同一次提交審覈流在deco系統中的裝修狀態爲未裝修,而在poi系統爲審覈中。一樣在4,5,6步驟的審覈回調過程也會有同類的狀態不一致問題。兩塊問題都是同一技術問題,本文只以1,2,3步提交過程爲例進行分析解決。數據庫

2、問題分析

1. 關係型數據事務在分佈式系統中的問題

      從業務中抽離出來,問題的核心緣由可用下圖流程模型來描述。服務器

系統A的某個業務功能包含兩步操做,第一步把數據寫入A系統本地庫,第二步遠程調用系統B,這兩步操做在A系統用一個數據庫事務來包裝。僞代碼以下:網絡

 1 $db->begain();
 2 // 第一步操做本地數據庫
 3 $res = $db->update($sql_a);
 4 if (!$res) {
 5     $db->rollback();
 6     return;
 7 }
 8 // 第二步遠程調用B系統
 9 $res = $http_request->get($url_b);
10 if ('success' != $res) {
11     $db->rollback();
12     return;
13 }
14 $db->commit();

第一步有兩種結果成功、失敗,第二步則有3種結果成功、失敗、超時,其中致使超時緣由多是網絡中斷,也多是B系統服務異常。那麼咱們根據兩步驟的執行結果狀況來分別分析一下是否會致使A、B系統之間的數據不一致。異步

可得當第一步執行成功,第二步遠程調用超時時,A系統事務會回滾,那麼就發生A、B系統數據不一致的狀況,A庫中寫入失敗,可是B庫中卻成功寫入。咱們習慣於使用關係型數據庫事務的ACID特性來達到一致性的目的,可是當事務中發生跨系統的調用時ACID就無效了,只從數據庫層面來看,跨系統就意味着同一個業務存在多個數據副本,對應着不一樣的數據庫實例,並且分佈在不一樣的機器上,而關係型數據庫的事務只是針對同一個庫的同一個connection而言的。分佈式


2.那麼怎麼解決跨系統的數據一致性問題?

     咱們先從新認識一下什麼是一致性?首先想到的是關係型數據庫事務,又會想到最經典的甲給乙轉錢的例子,事務的四大基本特性ACID保證了甲帳戶扣錢和乙帳戶入錢同時發生或同時不發生,其中的C特性就是指一致性,它是指數據庫事務不能破壞關係數據的完整性以及業務邏輯上的一致性。在web2.0以前大部分網站或者項目都是單系統,對應底層存儲也只是單數據庫,因此使用數據庫自己的事務特性就知足了一致性。 微服務

 

      可是隨着互聯網用戶和數據量的指數級增加,對於每一個系統的計算能力、吞吐量以及響應速度的要求都大大提升,因而單節點服務器確定知足不了要求,因此都在考慮拆分和系統擴展性,不管是通過水平拆分仍是垂直拆分,單機系統就變成了分佈式系統,分佈式系統就確定存在某節點或者網絡故障的狀況,以前說的事務的ACID中的強一致性就沒法保證。 網站

 

      再回到咱們的問題上來,poi系統其實就能夠理解爲垂直拆分出的一個微服務,deco調用poi的提交審覈接口就是分佈式系統之間的調用,可是deco中仍然用關係型數據庫的事務來達到強一致性的目的,根據CAP理論,分佈式系統的一致性、可用性、分區容錯性不可能同時獲得知足,只能知足其中兩個,而分佈式系統的分區容錯性都須要獲得知足,因此就須要在一致性和可用性之間進行取捨。Deco的這種實現其實就是爲了保證一致性,而犧牲了可用性。url

 

      而對於如今的系統而言,可用性是相當重要的必需要保證,要作到即便poi系統出現偶爾的網絡故障或者超時,也儘量不要用戶的一次提交失敗掉。

 

      再來了解一個概念BASE理論,BASE理論是CAP理論的一種實現,它對分佈式系統的一致性和可用性不可兼得的問題提出了一種方案,即基本可用和最終一致是目標。既然提到了強一致性和最終一致性,再介紹一下業界對一致性的分層次定義。

 

  • 強一致 :當更新操做完成以後,任何多個後續進程或者線程的訪問都會返回最新的更新過的值。這種是對用戶最友好的,就是用戶上一次寫什麼,下一次就保證能讀到什麼。根據 CAP 理論,這種實現須要犧牲可用性。

     

  • 弱一致 :系統並不保證續進程或者線程的訪問都會返回最新的更新過的值。系統在數據寫入成功以後,不承諾當即能夠讀到最新寫入的值,也不會具體的承諾多久以後能夠讀到。

     

  • 最終一致 :弱一致性的特定形式。系統保證在沒有後續更新的前提下,系統最終返回上一次更新操做的值。在沒有故障發生的前提下,不一致窗口的時間主要受通訊延遲,系統負載和複製副本的個數影響。DNS 是一個典型的最終一致性系統。

      對上面幾段分析的總結就是:關係型數據庫的事務能夠知足單系統的強一致性,大部分分佈式系統只能把最終一致性做爲追求。而咱們的deco和poi系統顯然也是應該追求最終一致性,由於對於poi和deco之間裝修審覈數據出現短期的不一致是徹底能夠接受的。

 

3、解決方案

 

      基於上述理論,咱們能夠有如下兩種方案來達到可用性和最終一致性:

解耦,異步任務處理,由原來同步調用poi系統變爲異步調用,將deco系統信息入庫和調用poi建立審覈任務這兩個操做分開。

  1. deco系統收到用戶請求以後先信息入庫,而後在本地數據庫同時新建一個任務(任務初始狀態爲待執行),當調用poi完成以後該任務改成已經執行,信息入庫和建立任務在同一個數據庫事務下。

  2. 後臺定時腳原本執行待執行狀態的任務。

  3. 若是異步調用poi返回失敗,則須要對以前入庫的信息進行回退。

  4. 若是異步調用poi遇到網絡問題或者超時,則考慮重試機制,注意重試機制要避免重複提交,可採起在deco系統重試前確認 或者 在poi系統保證接口的冪等性。

方案2、

      引入消息隊列,至關於對方案一的升級版。

  1. deco系統爲消息生產者,poi系統爲消息消費者。

  2. 生產者接收到用戶請求,業務數據處理入庫,而後寫入一條任務到消息隊列,而且要新建一張消息狀態表用於記錄消息的執行狀態,以上三個操做要在同一個本地事務中進行。其實也能夠在業務表增長一個字段用來表示消息執行狀態,這樣有一個缺點就是生產消息和自己業務處理髮生耦合,可是能夠接受,由於既然放在一個事務中耦合就不可避免。

  3. 消費者取出一條消息,進行業務處理,處理完成後須要告訴Deco系統消息執行結果,成功或者失敗,若是失敗須要從新把消息寫入隊列,注意這裏說的失敗並非業務處理的正常返回「失敗」狀態,而是因爲一些異常緣由致使業務處理沒有正常完成的狀況。Poi系統方須要重試時纔會發送失敗的通知。

  4. 要保證最終一致性,該方案還有一個關鍵點是消息隊列自己的可靠性和寫數據庫和寫消息隊列事務的一致性。好比淘寶的notify的兩階段提交機制就是爲了知足這一點。也能夠參考糯米技術文章平臺有一篇技術文章《輕量級高可靠消息隊列》

 

4、總結

  1. 對於單機單庫系統,數據一致性可經過關係型數據庫的事務來知足,並且ACID特性中的C是指強一致性,各數據庫自己都支持,並且很成熟。

  2. 分佈式系統則須要以BASE理論做爲指導,即以基本可用性和最終一致性做爲目標。

  3. 遠程RPC調用是一致性問題主要緣由,異步解耦+消息隊列可做爲分佈式系統知足最終一致性的優秀方案。

相關文章
相關標籤/搜索