1. 程式人生 > >分布式系統一致性問題解決實戰

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

eco系統 避免 vpd 由於 處理 原因 update 進程 機器

一、背景及問題描述

業務背景:

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

問題:

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

二、問題分析

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

從業務中抽離出來,問題的核心原因可用下圖流程模型來描述。
技術分享圖片
系統A的某個業務功能包含兩步操作,第一步把數據寫入A系統本地庫,第二步遠程調用系統B,這兩步操作在A系統用一個數據庫事務來包裝。偽代碼如下:

$db->begain();

// 第一步操作本地數據庫

$res = $db->update($sql_a);

if (!$res) {

$db->rollback();

return;

}

// 第二步遠程調用B系統

$res = $http_request->get($url_b);

if (‘success‘ != $res) {

$db->rollback();

return;

}

$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的這種實現其實就是為了保證一致性,而犧牲了可用性。

而對於現在的系統而言,可用性是至關重要的必須要保證,要做到即使poi系統出現偶爾的網絡故障或者超時,也盡可能不要用戶的一次提交失敗掉。

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

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

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

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

對上面幾段分析的總結就是:關系型數據庫的事務可以滿足單系統的強一致性,大部分分布式系統只能把最終一致性作為追求。而我們的deco和poi系統顯然也是應該追求最終一致性,因為對於poi和deco之間裝修審核數據出現短時間的不一致是完全可以接受的。

三、解決方案

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

方案一、
技術分享圖片
解耦,異步任務處理,由原來同步調用poi系統變為異步調用,將deco系統信息入庫和調用poi創建審核任務這兩個操作分開。

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

後臺定時腳本來執行待執行狀態的任務。

如果異步調用poi返回失敗,則需要對之前入庫的信息進行回退。

如果異步調用poi遇到網絡問題或者超時,則考慮重試機制,註意重試機制要避免重復提交,可采取在deco系統重試前確認 或者 在poi系統保證接口的冪等性。

方案二、

引入消息隊列,相當於對方案一的升級版。
技術分享圖片
deco系統為消息生產者,poi系統為消息消費者。

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

消費者取出一條消息,進行業務處理,處理完成後需要告訴Deco系統消息執行結果,成功或者失敗,如果失敗需要重新把消息寫入隊列,註意這裏說的失敗並不是業務處理的正常返回“失敗”狀態,而是由於一些異常原因導致業務處理沒有正常完成的情況。Poi系統方需要重試時才會發送失敗的通知。

要保證最終一致性,該方案還有一個關鍵點是消息隊列本身的可靠性和寫數據庫和寫消息隊列事務的一致性。比如淘寶的notify的兩階段提交機制就是為了滿足這一點。也可以參考其它技術文章平臺有一篇技術文章《輕量級高可靠消息隊列》

四、總結

對於單機單庫系統,數據一致性可通過關系型數據庫的事務來滿足,而且ACID特性中的C是指強一致性,各數據庫本身都支持,而且很成熟。

分布式系統則需要以BASE理論作為指導,即以基本可用性和最終一致性作為目標。

遠程RPC調用是一致性問題主要原因,異步解耦+消息隊列可作為分布式系統滿足最終一致性的優秀方案。

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