消息服務框架(MSF)應用實例之分散式事務三階段提交協議的實現

来源:https://www.cnblogs.com/bluedoctor/archive/2017/12/29/8146604.html
-Advertisement-
Play Games

分散式事務常常使用2階段提交或者3階段提交,那麼這兩種方式的區別是什麼?3階段提交協議是不是就完美了?圖文解釋,簡單易懂。 ...


一,分散式事務簡介

在當前互聯網,大數據和人工智慧的熱潮中,傳統企業也受到這一潮流的衝擊,紛紛響應國家“互聯網+”的戰略號召,企業開始將越來越多的應用從公司內網遷移到雲端和移動端,或者將之前孤立的IT系統聯網整合,或者將原來厚重的企業應用拆分重組,獨立成一個個輕量級的應用對外提供服務,這對傳統的業務處理的數據一致性,帶來了嚴重的挑戰,我們已經身處一個分散式的計算環境,分散式事務的需求越來越普遍。

舉一個例子,某行業電商網站經過幾年的發展,業務數據累積越來越多,查詢越來越慢。經過內部評審分析,認為系統的瓶頸就是資料庫壓力過大,如果要解決這問題,必須分表分庫,比如將訂單,商品,用戶分佈到不同的資料庫去,但這樣隨之帶來一個問題,原來處理業務的時候使用的是本地事務,分庫後就需要使用分散式事務了。

那麼應該如何實現分散式事務呢?

這裡我們需要明確一點,並非資料庫天然就是分散式的在執行操作的,事務都是在一個資料庫實例上進行的,如果要執行一個分散式事務的操作,那麼就需要協調多個分散的資料庫上執行的事務操作。所以在分散式事務中,有2個概念:

l  Distributed Transaction Resource Owner (簡稱DTR):

n  --分散式事務資源伺服器,擁有事務資源的伺服器,如絕大部分關係資料庫,一些消息隊列,或者一些能夠執行類似事務操作的應用。

l  Distributed Transaction Coordinate Controller (簡稱DTC):

n  --分散式事務協調控制器,它協調控制分散式事務環境中的事務資源伺服器,發送指令給它們並且處理事務資源伺服器返回的結果。

 

二,分散式事務的實現層面

 

在分散式事務的具體實現層面,可以在資料庫層直接實現,也可以在應用服務層面實現。如果是在應用服務層面實現,本質上它也可能是調用本地的資料庫事務。

下麵是DTR與DTC的拓撲關係圖:

基於關係資料庫層面介面實現的分散式事務

基於資料庫的分散式事務,一般在應用程式的數據層調用系統的分散式事務組件,應用程式執行本地事務的時候,先選舉出一個分散式事務協調器,然後協調器來協調各個本地事務的執行。由於是在應用程式的數據層進行的調用,所以它對遠程資料庫的操作是在本地進程內的。如果你的應用部署在多台伺服器上,那麼在每一臺操作資料庫的應用伺服器上都要安裝運行分散式事務協調器服務。

基於應用服務層面實現的分散式事務

 

基於應用服務層面的分散式事務,是在應用服務層面進行的事務控制,它同樣會有分散式事務協調控制器,和事務資源伺服器。與基於資料庫層面的分散式事務不同,事務的類型支持更廣泛,比如消息隊列訪問,文件寫入或者具有補償操作的業務應用程式,都可以成為事務資源,並且不要求這些事務資源本身支持分散式事務。舉個例子,事務資源A是Windows上的SQLSERVER資料庫,事務B是Linux上的MySQL資料庫,這時候事務B就沒法使用Windows上的事務協調控制器MSDTC了。而基於服務層面的分散式事務,可以解決這個問題。

三,分散式事務的2階段提交協議(2PC)

第一階段(1PC):提交投票階段

協調器向事務資源伺服器發出 CanCommit 的是否可以提交事務的詢問指令,事務資源伺服器收到此指令後,準備好要提交的事務資源,再向協調器回覆 YES;如果沒有準備好,比如執行事務中的操作出現了錯誤,應該回覆 NO.如果某DTR無法回覆,DTC也認為該DTR的結果是NO.

第一階段,全部回覆為YES,代表各個事務資源伺服器均已經準備好了提交。

 

第一階段,事務資源伺服器DTR-2回覆為NO,如果DTC等待DTR-2超過設定時間都沒有得到回覆,或者DTR-2與DTC斷開了連接,也認為DTR-2的結果是NO

 

第二階段(2 PC):提交或終止階段

協調器統計所有事物資源伺服器的回覆數量,如果全部回覆為YES,則向所有事物資源伺服器發出Commit指令,否則,發出Abort指令。資源伺服器收到指令後,執行相應的操作。

二階段提交事務的數據不一致問題

在第二階段(2PC),如果DTR沒有收到DTC的指令改怎麼辦呢?

如果等到超時都沒有收到DTC的指令,DTR處於“可以提交”或者“不可以提交”的雙重狀態,也就是提交狀態不可知。假設DTR1沒有收到DTC的提交指令或者撤銷指令,DTR1可以假設DTR2也不會收到指令,因為此時大概率是DTC宕機或者網路整體不良,那麼DTR1最佳的做法是回滾事務。

但是,如果僅僅是DTR1受網路影響沒有收到提交指令,而DTR2收到了提交指令,那麼DTR1回滾事務,DTR2提交了事務,整個分散式事務就是失敗的,數據發生了不一致。

因此,2階段提交的分散式事務不是高可靠的分散式事務控制模型,需要在事務資源的提交環節做更多的驗證,這便是3階段提交的分散式事務。

 

不過,對於大部分系統,2階段提交的分散式事務已經能夠滿足應用了,因為通常情況下,都是基於資料庫應用層實現的分散式事務,並且各個事務資源節點都在同一個區域網內,發生網路不穩定的概率非常小,並且現在不少資料庫都會做高可靠性的資料庫集群,發生宕機的可能性也非常小,最終出現數據不一致的概率也就非常小了。

 

如果系統的應用環境不能滿足上面說的任何一個條件,即分散式事務的控制不是在資料庫應用層,子系統不在一個區域網,或者資料庫沒有做高可靠的集群,並且對於系統的事務一致性要求非常高,那麼應該使用3階段提交協議來實現分散式事務。

四,分散式事務的3階段提交協議(3PC)

對2階段提交協議的分析我們發現,2PC的事務提交階段狀態是不確定的,整個事務容易出現不一致的情況。所以,我們隊2PC的提交階段,進一步拆分成“預提交”階段和提交階段,增加事務提交狀態的確認過程。

第一階段(1PC):提交投票階段

協調器向事務資源伺服器發出 CanCommit 的是否可以提交事務的詢問指令,事務資源伺服器收到此指令後,準備好要提交的事務資源,再向協調器回覆 YES;如果沒有準備好,比如執行事務中的操作出現了錯誤,應該回覆 NO.如果某DTR無法回覆,DTC也認為該DTR的結果是NO.

該階段的處理過程跟2階段提交協議的第一階段是一樣的,處理流程圖參考前面,此略。

 

第二階段(2 PC):預提交或終止階段

預提交事務

協調器(DTC)統計所有事務資源伺服器(DTR)的回覆數量,如果全部回覆為YES,則向所有事物資源伺服器發出PreCommit指令,否則,發出Abort指令。資源伺服器收到指令後,執行相應的操作。

在第二階段,如果DTR收到PreCommit指令,則向DTC回覆ACK消息,表示收到了指令,準備提交,接著,進入第三階段,等待最終的提交指令。

 

終止事務

在第二階段,如果在第一階段有節點異常,DTC發出撤銷指令,DTR收到了撤銷指令,那麼它執行回滾本地事務的操作。如果由於網路原因,某個DTR一直等到超時都沒有收到PreCommit指令,那麼它執行Abort撤銷指令,回滾本地事務。

 

第三階段(3 PC):提交或終止階段

提交分散式事務

協調器(DTC)統計所有事務資源伺服器(DTR)在第二階段的回覆數量,如果全部回覆為ACK,則向所有DTR發出Commit指令。DTR收到指令後,執行事務提交操作,並返回Commit Done消息,DTC收到此消息,結束整個分散式事務過程。

 

 

回滾分散式事務

協調器(DTC)統計所有事務資源伺服器(DTR)在第二階段的回覆數量,如果未收到全部回覆為ACK,則它認為有節點可能出現了網路故障,此節點沒有收到PreCommit指令或者雖然收到了卻沒有回覆ACK,測試DTC應該向所有DTR節點發出撤銷指令。各DTR收到撤銷指令後,回滾本地事務,然後回覆消息,DTC完成本次事務過程。

 

三階段提交事務也並不完美

考察第3階段的提交分散式事務的情況,DTR1收到了Commit指令,但是由於網路原因,DTR2沒有收到此指令,那麼DTR2是提交本地事務還是回滾本地事務?

站在DTR2的角度,它在本階段可能收到Commit指令,也可能收到Abort指令,那麼它既可以提交本地事務也可以回滾本地事務,兩種操作是不確定的,所以,3階段提交協議,仍然不是完美的,不能百分之百保證數據的最終一致性。

既然3階段提交協議仍然有不確定性,那麼相比2階段提交協議有什麼意義呢?

 

仔細想下,DTR2已經進入第3階段了,那麼肯定其它DTR都進入了第3階段,而進入第3階段的前提是各DTR節點都收到過PreCommit指令,都是已經準備好提交只等最後的提交指令了,否則各節點在第二階段應該收到撤銷指令,不會再進入第三階段。既然各DTR節點都進入了第三階段,它們都準備好提交事務了,那麼即使沒有收到最終的Commit指令,DTC發出Commit指令也是大概率的。所以,從概率上講,如果在第三階段,DTR沒有收到Abort撤銷指令,也沒收到Commit提交指令,那麼它預設應該指向Commit指令,提交本地事務。相比第二階段某DTR節點沒有收到指令而認為應該收到PreCommit指令的概率,要大得多。

 

關於第三階段沒有收到指令而應該大概率執行Commit指令的問題,理解起來可能有點困難,我給同事講的時候大部分同事也難以理解,可能是我表述的問題,大家有更好的解釋方式,歡迎交流,不勝感激!

 

5,實現 3階段提交的分散式事務

本文將介紹一個基於服務層面而不是資料庫層面的,3階段提交的分散式事務中間件的設計開發過程。這個中間件必須解決下麵幾個問題:

l  通信組件—分散式事務控制器(DTC),分散式事務資源伺服器(DTR)都是獨立的服務,這些服務部署在不同的通信節點,它們之間需要進行可靠的網路通信,因此通信組件是基礎;

l  數據訪問組件—提供基礎的數據讀寫操作,並且能夠操作本地事務。

l  服務組件—將DTC,DTR的功能代碼編寫為相應的SOA服務組件

l  關係資料庫—具有事務功能的關係資料庫,可以是嵌入式的本地資料庫,比如SQLite,也可以是伺服器客戶機模式的網路資料庫,比如SQLSERVER。

 

各組件的關係圖如下:

 

PDF.NET的消息服務框架(MSF)具有開發服務組件基礎的介面和一套消息通信組件,同時還有一個服務容器,可以承載本篇文章說的分散式事務控制器DTC,分散式事務資源服務DTR這些服務應用,同時PDF.NET還有一個強大的數據訪問組件 PDF.NET SOD,下一篇文章,我們將來具體討論基於MSF和SOD的3階段分散式事務應用的實現過程,它的源碼已經發佈在 https://github.com/bluedoctor/MSF-DistTransExample ,大家可以先睹為快。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • AOP的概念,使用過Spring的人應該都不陌生了。Dojo中,也是支持AOP的。對於JavaScript的其他框架、庫不知道有沒有AOP的支持。相信即便沒有支持,也不會太遠了。下麵就介紹一下使用JavaScript實現AOP。 AOP的思想就是在目標方法前後加入代碼: var result=nul ...
  • 相容性 相容性:瀏覽器相容問題和適配問題統稱為相容性問題 解決辦法 1.hack語法,控制解決辦法 <!--[if <keywords>? IE <version>?]> HTML代碼塊 <![endif]--> eg:<!--[if gt IE 6]> ...... <![endif]--> 說明 ...
  • JS實現的4種數字千位符格式化方法 所謂的數字千分位形式,即從個位數起,每三位之間加一個逗號。例如“10,000”。針對這個需求,我起初寫了這樣一個函數: // 方法一 function toThousands(num) { var result = [ ], counter = 0; num = ...
  • 呃,終於到了這地方…… MMP,有31個函數,估計可以寫到明年了。 這裡先梳理所有事件的註入來源,經檢測,全部來源於WebpackOptionsApply中,回到那個可怕的模塊,梳理後如下: 還好都集中在一個地方,這樣又可以寫流水賬了。 這裡先要過一個地方,之前似乎遺留了: 這裡註入了entry-o ...
  • 在很久之前就想通過工具來規範自己的代碼風格,減少程式出錯的概率,如果看過我的 一個前端程式猿的Sublime Text3的自我修養 ,這篇博客的朋友,肯定知道在當時我使用 SublimeLinter-jshint 插件來規範風格,但是實際上一直懶癌發作也沒去看它的文檔,使用著它預設的規則。不過現在是 ...
  • 1、Vue實例常用屬性 (1)數據 data:Vue 實例的數據對象 components:Vue實例配置局部註冊組件 (2)類方法computed:計算屬性 watch:偵聽屬性 filters:過濾器 methods:Vue實例方法 render:渲染函數,創建虛擬DOM (3)生命周期crea ...
  • 1.內聯式引用:直接用在標簽上,但維護成本高 2.外部連接式引用:css代碼與html代碼分離,便於代碼重覆使用 style.css文件內容如右: 3.內部式引用:頁面較為清晰,但不能被別的頁面使用 4.外部導入式:可以在一個HTML文件中導入多個樣式表。類似於外部鏈接式引用 在HTML文件中hea ...
  • "Parcel" 是一個零配置的網路應用打包工具, 適用於經驗不同的開發者, 它利用多核處理提供了極快的速度。對比 webpack 最大的兩個亮點: 零配置 極快速 omi 相關的插件都是基於 webpack 進行開發,今天正式投入 Parcel 懷抱。 準備工作 通過 yarn 或 npm 安裝 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...