微服務架構及分散式事務解決方案

Java架構技術棧發表於2019-03-26

分散式事務

分散式事務場景如何設計系統架構及解決資料一致性問題,個人理解最終方案把握以下原則就可以了,那就是:大事務=小事務(原子事務)+非同步(訊息通知),解決分散式事務的最好辦法其實就是不考慮分散式事務,將一個大的業務進行拆分,整個大的業務流程,轉化成若干個小的業務流程,然後通過設計補償流程從而考慮最終一致性。

什麼是事務

事務(Transaction)及其ACID屬性

事務是由一組SQL語句組成的邏輯處理單元,事務具有以下4個屬性,通常簡稱為事務的ACID屬性:

  1. 原子性(Atomicity):事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。

  2. 一致性(Consistent):在事務開始和完成時,資料都必須保持一致狀態。這意味著所有相關的資料規則都必須應用於事務的修改,以保持資料的完整性;事務結束時,所有的內部資料結構(如B樹索引或雙向連結串列)也都必須是正確的。

  3. 隔離性(Isoation):資料庫系統提供一定的隔離機制,保證事務在不受外部併發操作影響的“獨立”環境執行。這意味著事務處理過程中的中間狀態對外部是不可見的,反之亦然。

  4. 永續性(Durabe):事務完成之後,它對於資料的修改是永久性的,即使出現系統故障也能夠保持。

典型場景:銀行轉賬業務

例如:李雷賬戶中有500塊錢,韓梅梅賬戶有200塊錢,李雷要從自己的賬戶中轉100塊錢給韓梅梅,轉賬(事務)成功執行完成後應該是李雷賬戶減100變為400,韓梅梅賬戶加100變為300,不能出現其他情況,即在事務開始和結束時資料都必須保持一致狀態(一致性),事務結束時所有的資料及結構都必須是正確的。並且同樣的轉賬操作(同一流水,即一次轉賬操作)無論執行多少次結果都相同(冪等性)。

電商場景:流量充值業務

再說我們做的一個專案:中國移動-流量充值能力中心,核心業務流程為:

  1. 使用者進入流量充值商品購買頁面,選擇流量商品;

  2. 購買流量充值商品,有庫存限制則判斷庫存,生成流量購買訂單;

  3. 選擇對應的支付方式(和包、銀聯、支付寶、微信)進行支付操作;

  4. 支付成功後,近實時流量到賬即可使用流量商品;

此業務流程看似不是很複雜對吧,不涉及到類似電商業務的實物購買,但是我認為其中的區別並不是很大,只是缺少電商中的物流發貨流程,其他流程幾乎是一樣的,也有庫存以及優惠折扣等業務存在。

整個系統互動如下圖:

微服務架構及分散式事務解決方案

分散式事務

上述兩個場景的業務需求已經說完了,接著談談分散式事務,要說分散式事務那就先聊聊本地事務與分散式事務:

相同點:首先都是要保證資料正確(即ACID),本地事務與分散式事務還可以對應為:剛性事務與柔性事務,在我個人理解剛性事務與柔性事務的最大區別就是:一個完整的事務操作是否可以在同一物理介質(例如:記憶體)上同時完成;柔性事務就是一個完整事務需要跨物理介質或跨物理節點(網路通訊),那麼排它鎖、共享鎖等等就沒有用武之地了(這裡並不是指大事務拆小事務【本地事務】後),無法保證原子性(Atomicity)完成事務。個人理解分散式(柔性)事務本質意義上就是-偽事務,柔性事務其實就是根據不同的業務場景使用不同的方法實現最終一致性,因為可以根據業務的特性做部分取捨,在業務過程中可以容忍一定時間內的資料不一致。

支付寶的柔性事務實現方式有四種分別針對不同的業務場景,如下圖:

微服務架構及分散式事務解決方案

  1. 兩階段型

  2. 補償型

  3. 非同步確保型

  4. 最大努力通知型

流量交易中心的業務場景

通過Dubbo實現了微服務化,大致拆分如下:

  1. 商品服務

  2. 訂單服務

  3. 庫存服務

  4. 支付服務

  5. 直充服務

  6. 訊息服務

  7. 等其他服務

場景一:

庫存數量與訂單數量一致性,採用補償型+最大努力通知型,採用原因為不涉及跨機房和長事務(正常情況下庫存與訂單服務處理很快):

  1. 使用者下單先減庫存,庫存減成功後;

  2. 呼叫下單服務:

  3. 2-1. 下單成功,兩事務均提交完成;

  4. 2-2. 下單失敗,庫存回滾,兩事務均失敗,此處還有一個保障機制(最大努力通知型),就是如果呼叫庫存服務異常,確定庫存回滾失敗了,則放入訊息服務(延時訊息佇列)分階段定時重試,努力重試保證庫存服務正常後成功回滾。

場景二:

訂單資訊、支付資訊、充值資訊三者之間的一致性,採用非同步確保型的原因是,整個業務鏈路太長且跨不同的機房系統,網路延遲較高,業務方面恰好不需要非常高的實時性,所以採用小事務+非同步通知,目前正常情況下使用者從下單到完成支付到流量到賬平均為1-5分鐘左右:

  1. 下單成功即訂單服務建立訂單成功併傳送支付請求到支付閘道器係統(訂單狀態-待支付,超過1小時未支付則流轉為超時未付撤銷,此處用到了RocketMQ的延時消費恰好實現定時器業務場景)。

  2. 返回支付頁面,使用者在支付交易系統完成支付業務流程,支付閘道器非同步通知流量中心,流量中心接收到支付成功狀態後修改訂單狀態-支付成功,並給支付閘道器返回成功結果(此處併發壓力目前不大,暫時沒有再進行非同步解耦)。

  3. 流量中心修改完訂單狀態後,呼叫訊息服務將直充業務放入訊息佇列,對直充業務進行解耦(原因是直充需要呼叫31省移動CRM系統,此鏈路過長,且部分省CRM系統耗時非常大,每個省的處理能力不同,經常出現20秒以上的超時,因此要考慮部分超時較高的省份拖垮系統,進行業務的削峰填谷);

  4. 3-1. 當直充成功時,修改訂單狀態-已完成;

  5. 3-2. 當直充失敗時(移動特性,例如:直充時正好使用者銷戶或者停機了),修改訂單狀態為待退款,並呼叫支付閘道器係統的退款介面,退款成功後支付閘道器非同步通知流量中心,流量中心修改訂單狀態為-退款成功;

  6. 3-3. 當直充超時時,呼叫定時任務服務進行超時重試機制(第一次重試在10分鐘後執行、第二次在30分鐘後、第三次…..),直到最大超時重試次數後還得不到直充結果,訂單狀態會卡在支付成功狀態,依賴T+1對賬稽核流程保證最終一致性,訂單狀態根據對賬結果流轉為:已完成或待退款–>退款成功。

場景三:

直充到賬後的訊息通知(APP訊息推送或簡訊通知),採用最大努力通知型,這個業務場景比較簡單,在直充成功後,訂單狀態流轉為已完成,此時通過訊息服務進行到賬通知業務的解耦,呼叫訊息服務失敗的情況下,使用定時任務努力通知。

場景四:

對賬稽核:

按照支付賬期每日進行T+1對賬,對賬原則:以支付交易記錄為準,對流量中心訂單記錄+支付閘道器交易記錄+省CRM充值記錄三方比對,將某些中間狀態的訂單(例如:支付成功、待退款)核對後將訂單狀態流轉完結(已完成、退款成功)。

結算稽核:

對賬成功後的資料定期進入結算流程,對支付閘道器週期內的支付金額與結算資料的金額進行核對,稽核成功後進行財務結算流程,將錢結算給省公司,並提供結算明細給省公司,供省公司與直充成本記錄進行復核。

以下是流量中心的部分架構設計,總體原則方向:微服務化

流量中心-架構設計

微服務架構及分散式事務解決方案

架構設計思想:在系統初期設計時以及部分硬性環境約束下,我們根據業務拆分為多個子系統(微服務):商品服務、訂單服務、庫存服務、支付閘道器、統一介面平臺、對賬服務、結算服務、閘道器對接服務等,後續還會增加:賬戶服務、虛擬貨幣服務、卡券服務等等…。按照微服務的核心設計思想,所有服務完全獨立、隔離,因此所有服務從上至下:請求接入(連線管理)、請求處理(計算服務)、資料儲存(儲存服務)進行拆分,接入與計算盡最大可能實現無狀態,資料儲存進行垂直+水平拆分,垂直拆分:商品庫-mysql(讀多寫少,主從架構+讀寫分離)+redis(讀多寫少,叢集方式)、訂單庫-mysql(讀寫均衡,多主多從+水平拆分)、庫存專用庫-redis(分散式+主備容災)、外部交易系統-支付閘道器、外部辦理系統-統一介面平臺。

此架構目前已支撐總交易額3.6億,總訂單4680萬,日均交易額500萬,日訂單量50萬,後續業務量持續增加的情況下按照微服務思想繼續拆分,例如將訂單服務再拆分為:下單服務、查單服務,直到根據業務需求與系統關係耦合性拆分到最細粒度為止。

  1. 效能擴充套件:應用層計算服務(無狀態應用)通過增加服務節點同比提升運算效能,配套質量(效能)監控服務dubbo monitor及整合Netflix的Hystrix熔斷器對業務質量進行管理實現應用層的動態擴縮容。

  2. 容量擴充套件:資料層儲存服務(有狀態應用)通過對資料水平拆分實現容量的無限擴容,Nosql類方案:Codis中介軟體;關係型資料庫:Mycat資料庫分庫分表中介軟體。目前專案中採用twitter的snowflake唯一ID生成器(根據業務場景優化後)自己實現資料的水平拆分和路由規則。

  3. 儲存效能:Nosql:針對讀多寫少場景-使用淘寶的Tedis(多寫隨機讀的特性提高效能),讀寫均衡使用-Codis;Mysql:讀多寫少場景使用一主多從架構(例如商品資訊),讀寫均衡場景使用多主多從架構(例如訂單資訊)。

整體拆分原則如下圖:

微服務架構及分散式事務解決方案


相關文章