search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

淺談分散式事務控制在銀行應用的實現

對於分散式資料庫而言,分散式事務控制是重點和難點,一直以來沒有成熟的方案可以突破CAP理論,幾乎每個分散式資料庫研發團隊都在分散式事務控制方案上結合了各自應用特點,進行了針對性的取捨,可以說是八仙過海各顯神通。以下是我對分散式事務控制的理解:

分散式事務控制的最終目標是實現一致性,方案大體分為實時一致性和最終一致性兩種。兩階段提交是比較典型的實時一致性方案,提供補償事務和基於消息隊列的非同步處理方案是最終一致性方案。兩階段提交由於同步阻塞、存在臟讀可能性等問題,在某些銀行的應用場景下無法使用,如果將隔離級別修改為串列化則可以解決臟讀問題,但對性能影響較大。基於消息隊列的非同步處理方案將事務拆分成多個本地子事務,子事務之間通過消息隊列銜接,實現串列執行,單個子事務佔用資源的時間很短,併發度高。但這種最終一致性方案如果應用到銀行的應用中勢必影響用戶體驗,而且對應用侵略性較大,實施成本高。

在分析了以上事務處理方案的優缺點之後,根據銀行業務對實時一致性的要求,考慮到用戶體驗和實施成本的影響,我們提出了基於全局事務ID(Global transaction ID,以下簡稱GTID)的分散式事務解決方案。

基本原理

在基於GTID的分散式事務方案(以下簡稱本方案)中,我們把協調參與者和記錄全局事務狀態這兩個功能分開,用計算節點協調各事務參與者進行事務操作,全局事務管理器僅管理全局事務的狀態。為了確保事務狀態正常,全局事務管理採用了實時持久化和實時同步到備機等多重保障機制。本方案事務管理架構如圖1所示。

兩(三)階段提交的核心思想是通過前期的多次準備和協調工作,儘可能讓最後的提交操作能夠成功。而本方案認為大部分事務都可以一次提交成功,因此採用一階段提交+補償事務的方式,如果事務在提交階段有部分節點提交失敗,本方案將回滾已成功提交的事務,而不是讓失敗的節點不斷重試。與兩(三)階段提交相比,本方案在大部分情況下減少了與數據節點的交互次數,降低了鎖衝突概率,提升了事務處理效率。

建表時增加一個隱藏欄位,用於記錄GTID。

每個事務開始時為其申請一個GTID,該GTID是全局唯一且單調遞增的,GTID申請成功后,我們稱該GTID為活躍(Active)狀態,對應該GTID的事務狀態為未提交狀態,若涉及到數據更新,則將GTID更新到本事務將要更新的數據中,事務成功提交后,將GTID釋放,此時我們稱GTID為非活躍(UnActive)狀態,對應的事務狀態為已提交狀態。

當事務提交失敗時,提交失敗節點會自動回滾,對於已成功提交的節點,需要將其回滾,數據恢復到更新前的狀態,全部節點回滾完成後,同樣需要將GTID釋放。

事務的原子性

保證事務的原子性是分散式事物的最大難點,在分散式環境下,保證事務原子性主要有兩種方案,一種是在提交命令發出后不回滾,儘可能保證提交成功;另一種是在提交命令發出后,根據響應結果判斷是提交成功還是該進行回滾。

我們採用的是第二種方式,由於我們的方案採用的是普通事務的提交方式,目前的主流資料庫在本地事務提交后都不能回滾,我們必須自己實現已提交事務的回滾。已提交事務回滾架構如圖2所示。

在每個數據節點上部署一個回滾模塊用於已提交事務回滾,當部分數據節點提交失敗時,計算節點向已經提交成功的資料庫節點的回滾模塊發送已提交事務回滾命令,命令中包含事務對應的GTID,回滾模塊根據GTID進行回滾,步驟如下:

  • 定位:根據GTID相關信息定位要進行分析的資料庫日誌文件列表;

  • 查詢:遍歷資料庫日誌文件,找到GTID對應的事務日誌塊;

  • 分析:分析日誌塊,為事務中每條SQL語句生成反向SQL語句;

  • 執行回滾:將所有反向SQL語句逆序執行,並保證在一個事務中。

    由於該回滾操作不是資料庫原生回滾機制,在實際使用中需要經過大量優化才能保證回滾的性能達到可用級別。

事務的一致性

在單機資料庫事務中,事務的一致性是指事務的任何操作都不會使得數據違反資料庫定義的約束、觸發器等規則。在分散式資料庫中,由於數據分佈在不同節點,有些約束難以保證,比如主鍵和唯一性約束,中信銀行當前實現的版本未從資料庫本身保證該約束的完整性,只能從使用規範角度進行約束,由應用保證主鍵和唯一索引的全局唯一性。

事務的隔離性

事務隔離性的本質就是如何正確處理讀寫衝突和寫寫衝突,這在分散式事務中又是一個難點,因為在我們的分散式事務控制方案中,可能會出現提交不同步的現象,這個時候就有可能出現「部分已經提交」的事務。一旦併發應用訪問「已經提交」節點中的數據,就需要根據GTID的狀態來判斷是「部分提交」還是「全部提交」,否則就出現了分散式資料庫中特有的一種「臟讀」。因此GTID方案可以確保分散式事務的隔離性。

事務的持久性

和單機一樣,分散式事務也需要保證事務的持久性,通過單節點數據的持久化和全局事務狀態的持久化來完成,數據的持久化由單節點資料庫保證,全局事務狀態的持久化由全局事務管理器負責,全局事務管理器採用定時全量和實時增量方式實現事務狀態的持久化:將GTID申請和釋放的動作實時寫到磁碟,同時每隔一定時間將全局事務管理中的活躍GTID列表以非同步方式寫到磁碟,通過定時的全量活躍GTID列表和實時的增量記錄,可以獲得任意時刻的活躍GTID列表。

異常處理

分散式環境下,事務處理涉及的組件、伺服器和網路比單機複雜太多,各個環節都可能出現故障,因此異常處理也成為分散式事務的重點。根據故障環節的不同可分為數據節點異常、計算節點異常和全局事務管理器異常。

數據節點異常

數據節點異常時,全局事務將無法提交,已經提交的本地事務將會被回滾。具體考慮如下幾個場景(假設分散式事務涉及三個數據節點:DB1、DB2、DB3,其中DB2發生了異常):

1. 分散式事務還未發起提交:向DB1、DB3發起回滾操作,DB2的回滾由數據節點自身保證;

2. 分散式事務已經發起提交:DB2上也已提交,但結果未知。此時需要向所有數據節點發起已提交事務回滾。

計算節點異常

分散式事務正常運行時,計算節點(假設為計算節點A)發生異常,與數據節點集群及客戶端的所有連接都已中斷,數據節點上未提交的事務由數據節點自動回滾。客戶端通過其他計算節點(假設為計算節點B)重新建立連接進行資料庫集群訪問,不會影響業務新發起的事務,但由於計算節點A異常時,處於部分已提交狀態的事務將無法結束,計算節點B上的事務一旦訪問到這些事務涉及的數據就會被阻塞,直到這些事務回滾。

具體考慮以下兩種場景:

1. 每台計算節點上部署監控程序,當計算節點異常時,監控程序將重啟計算節點,重啟完成後由計算節點自己與全局事務管理器交互並完成異常事務的回滾;

2. 如果計算節點伺服器已經宕機且無法啟動或者監控程序無法重啟計算節點服務,則由計算節點管理器協調對等的計算節點(該集群的其他計算節點),完成異常事務的回滾。

全局事務管理器異常

全局事務管理器採用主備部署,申請或釋放GTID時通過實時同步到備機內存、實時增量持久化到本地磁碟、定時全量持久化三重保護機制確保全局事務信息不丟失。在單機異常時會進行主備切換,在雙機都異常時,需通過持久化的全局事務信息進行恢復。

組合異常

1. 組合異常,考慮如下兩種場景:

數據節點和計算節點同時異常。數據節點和計算節點走各自的異常處理流程即可解決問題,影響的是計算節點上的當前活躍事務以及涉及異常數據節點上的活躍事務的合集。

數據節點、計算節點和全局事務管理器全部異常。此時全局事務管理器上所有的GTID都需要回滾,可能需要先配置額外的計算節點,並通過計算節點管理器觸發所有活躍事務的2. 回滾。具體流程分析如下:

2-1. 所有未發起提交操作的分散式事務,數據節點恢復后將自動回滾;

2-2. 恢復計算節點,若計算節點不能恢復則需要配置額外的計算節點;

2-3. 由恢復后的計算節點或者計算節點管理器協調新的計算節點處理活躍事務的回滾,其中未發起提交操作的事務不會發生實際回滾動作(由第一步中的數據節點回滾),已經發起提交操作的事務將由數據節點上的回滾模塊完成已提交事務的回滾。

作者簡介

劉文濤,中信銀行軟體開發中心副處長,從事資料庫相關工作15年。擅長數據模型和關係資料庫,曾經在IBM LBS做過五年資料庫設計諮詢顧問。現負責中信銀行分散式資料庫和大數據兩個領域的研發工作。

本文為《程序員》原創文章,未經允許不得轉載,更多精彩文章請點擊「閱讀原文」訂閱《程序員》。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦