淺談分散式事務及解決方案

来源:https://www.cnblogs.com/jingdongkeji/archive/2023/10/17/17769531.html
-Advertisement-
Play Games

1 背景 在講述分散式事務的概念之前,我們先來回顧下事務相關的一些概念。 1.1 事務的基本概念 就是一個程式執行單元,裡面的操作要麼全部執行成功,要麼全部執行失敗,不允許只成功一半另外一半執行失敗的事情發生。例如一段事務代碼做了兩次資料庫更新操作,那麼這兩次資料庫操作要麼全部執行成功,要麼全部回滾 ...


1 背景

在講述分散式事務的概念之前,我們先來回顧下事務相關的一些概念。

1.1 事務的基本概念

就是一個程式執行單元,裡面的操作要麼全部執行成功,要麼全部執行失敗,不允許只成功一半另外一半執行失敗的事情發生。例如一段事務代碼做了兩次資料庫更新操作,那麼這兩次資料庫操作要麼全部執行成功,要麼全部回滾。

1.2 事務的基本特性

我們知道事務有4個非常重要的特性,即我們常說的(ACID)。

  • Atomicity(原子性):一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
  • Consistency(一致性):在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作。
  • Isolation(隔離性):資料庫允許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重覆讀(repeatable read)和串列化(Serializable)。
  • Durability(持久性):事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失

2 分散式事務

其實分散式事務從實質上看與資料庫事務的概念是一致的,既然是事務也就需要滿足事務的基本特性(ACID),只是分散式事務相對於本地事務而言其表現形式有很大的不同。

本地事務的時代,如果需要同時操作資料庫的多條記錄,而這些操作可以放到一個事務中,那麼我們可以通過資料庫提供的事務機制就可以實現。

而隨著微服務架構的推進,原本一個本地邏輯執行單元,被拆分到了多個獨立的微服務中,這些微服務又分別操作了不同的資料庫和表。

比如下個指派個體的運輸任務,下運輸任務的同時要生成需求、計劃、任務,還要去調用詢價服務,投保服務,那麼,一旦產生任何一個服務異常,都會產生事務性的問題。雖然對於我們現有邏輯來說,可以由運營作廢,但未來自動化之後呢?

分散式事務是為瞭解決微服務架構(形式都是分散式系統)中不同節點之間的數據一致性問題。這個一致性問題本質上解決的也是傳統事務需要解決的問題,即一個請求在多個微服務調用鏈中,所有服務的數據處理要麼全部成功,要麼全部回滾。當然分散式事務問題的形式可能與傳統事務會有比較大的差異,但是問題本質是一致的,都是要求解決數據的一致性問題。

而分散式事務的實現方式有很多種,最具有代表性的是由Oracle Tuxedo系統提出的XA分散式事務協議。XA協議包括兩階段提交(2PC)和三階段提交(3PC)兩種實現,接下來我們分別來介紹下這兩種實現方式的原理。

3 兩階段提交(2PC)

兩階段提交又稱2PC(two-phase commit protocol),2PC是一個非常經典的強一致、中心化的原子提交協議。這裡所說的中心化是指協議中有兩個角色:一個是分散式事務協調者(coordinator)和N個參與者(participant)。

3.1 2PC運行原理

兩階段提交,顧名思義就是要進行兩個階段的提交:第一階段,準備階段(投票階段);第二階段,提交階段(執行階段)。

3.1.1 準備階段(Prepare phase)

  1. 分散式事務的發起方,向分散式事務協調者(Coordinator,也可以叫事務管理TransactionManager)發送請求,
  2. Coordinator分別向參與者(Participant)A、參與者(Participant)B分別發送事務預處理請求,稱之為Prepare,有些資料也叫”Vote Request”。
  3. 此時這些參與者節點一般來說就會打開本地資料庫事務,然後開始執行資料庫本地事務,每個資料庫參與者在本地執行事務並寫本地的Undo/Redo日誌(Undo日誌是記錄修改前的數據,用於資料庫回滾,Redo日誌是記錄修改後的數據,用於提交事務後寫入數據文件),但在執行完成後並不會立馬提交資料庫本地事務,而是先向Coordinator進行“Vote Commit”的反饋,告知處理結果。
  4. 如果所有的參與者都向協調者做了“Vote Commit”的反饋的話,那麼流程進入第二個階段。

3.1.2 提交階段(commit phase)

1)如果所有參與者均反饋的是成功,協調者就會向所有參與者發送“全局提交確認通知(global_commit)”,參與者Participant就會完成自身本地資料庫事務的提交,並將提交結果回覆“ack”消息給協調者Coordinator,然後協調者Coordinator就會向調用方返回分散式事務處理完成的結果。如果有任何一個參與者返回失敗,則回滾事務。

2)如果參與者向協調者反饋“Vote_Abort”消息,即返回了失敗的消息。此時分散式事務協調者Coordinator就會向所有的參與者Participant發起事務回滾的消息(“global_rollback”),此時各個參與者就會回滾本地事務,釋放資源,並且向協調者發送“ack”確認消息,協調者就會向調用方返回分散式事務處理失敗的結果。

以上就是兩階段提交的基本過程了,那麼按照這個兩階段提交協議,分散式系統的數據一致性問題就能解決麽?

3.2 2PC存在的問題

其實,2PC只是通過增加了事務協調者(Coordinator)的角色來通過2個階段的處理流程來解決分散式系統中一個事務需要跨多個服務的數據一致性問題。

以下幾點是XA-兩階段提交協議中會遇到的一些問題:

  • 性能問題:2PC中的所有的參與者節點都為事務阻塞型,當某一個參與者節點出現通信超時,其餘參與者都會被動阻塞占用資源不能釋放。
  • 協調者單點故障問題:由於嚴重的依賴協調者,一旦協調者發生故障,而此時參與者還都處於鎖定資源的狀態,無法完成事務commit操作。雖然協調者出現故障後,會重新選舉一個協調者,可無法解決因前一個協調者宕機導致的參與者處於阻塞狀態的問題。
  • 網路閃斷導致腦裂:第二階段中協調者向參與者發送commit命令之後,一旦此時發生網路抖動,導致一部分參與者接收到了commit請求並執行,可其他未接到commit請求的參與者無法執行事務提交。進而導致整個分散式系統出現了數據不一致。

4 三階段提交(3PC)

三階段提交又稱3PC,在2PC的基礎上增加了CanCommit階段,並引入了超時機制。一旦事務參與者遲遲沒有收到協調者的Commit請求,就會自動進行本地commit,這樣相對有效地解決了協調者單點故障的問題。

4.1 3PC運行原理

4.1.1 CanCommit階段

  1. 協調者向參與者發出CanCommit ,進行事務詢問操作,所有參與者都反饋yes後,才能進入下一個階段。(這一個階段時不鎖表,不像2pc 第一個階段就開始鎖表,3pc的階段一是為了先排除個別參與者不具備提交事務能力的前提下,而避免鎖表。)簡單來說就是檢查下自身狀態的健康性。
  2. 有任何一個參與者反饋的結果是No,整個分散式事務就會中斷,協調者就會向所有的參與者發送“abort”請求。

4.1.2 PreCommit階段

  1. 在階段一中,如果所有的參與者都返回Yes的話,那麼就會進入PreCommit階段進行事務預提交。此時分散式事務協調者會向所有的參與者發送PreCommit請求,參與者收到後開始執行事務操作,並將Undo和Redo信息記錄到事務日誌中。參與者執行完事務操作後(此時屬於未提交事務的狀態),就會向協調者反饋“Ack”表示已經準備好提交,並等待協調者的下一步指令。
  2. 有任何一個參與者反饋的結果是No,或協調者在等待參與者節點反饋的過程中超時(2PC中只有協調者可以超時,參與者沒有超時機制)。整個分散式事務就會中斷,協調者就會向所有的參與者發送“abort”請求。

4.1.3 DoCommit階段

  1. 在階段二中如果所有的參與者都可以進行PreCommit提交,那麼協調者就會從“預提交狀態”->“提交狀態”。然後向所有的參與者發送”doCommit”請求,參與者在收到提交請求後,執行事務提交操作,並向協調者反饋“Ack”消息,協調者收到所有參與者的Ack消息後完成事務。
  2. 同樣,如果有一個參與者節點未完成PreCommit的反饋或者反饋超時,那麼協調者都會向所有的參與者節點發送abort請求,從而中斷事務。

相比較2PC而言,3PC對於協調者(Coordinator)和參與者(Participant)都設置了超時時間,解決了參與者在長時間無法與協調者節點通訊(協調者掛掉了)的情況下,無法釋放資源的問題,因為參與者自身擁有超時機制會在超時後,自動進行本地commit從而進行釋放資源。而這種機制也側面降低了整個事務的阻塞時間和範圍。
另外,通過CanCommit、PreCommit、DoCommit三個階段的設計,相較於2PC而言,多設置了一個緩衝階段保證了在最後提交階段之前各參與節點的狀態是一致的。

3PC的缺點:

3PC在去除阻塞的同時也引入了新的問題,那就是參與者接收到precommit消息後,如果出現網路分區,此時協調者所在的節點和參與者無法進行正常的網路通信,在這種情況下,該參與者依然會進行事務的提交,這必然出現數據的不一致性。

5 補償事務(TCC)

TCC與2PC、3PC一樣,只是分散式事務的一種實現方案。

5.1 TCC原理:

TCC(Try-Confirm-Cancel)又稱補償事務。其核心思想是:”針對每個操作都要註冊一個與其對應的確認和補償(撤銷操作)”。它分為三個操作:

  • Try階段:主要是對業務系統做檢測及資源預留,比如說凍結庫存。
  • Confirm階段:確認執行業務操作。
  • Cancel階段:取消執行業務操作。

TCC事務的處理流程與2PC兩階段提交類似,不過2PC通常都是在跨庫的DB層面,而TCC本質上就是一個應用層面的2PC,需要通過業務邏輯來實現。這種分散式事務的實現方式的優勢在於,可以讓應用自己定義資料庫操作的粒度,使得降低鎖衝突、提高吞吐量成為可能。

而不足之處則在於對應用的侵入性非常強,業務邏輯的每個分支都需要實現try、confirm、cancel三個操作。此外,其實現難度也比較大,需要按照網路狀態、系統故障等不同的失敗原因實現不同的回滾策略。為了滿足一致性的要求,confirm和cancel介面還必須實現冪等。

TCC的具體原理圖如下:

5.2 註意事項:

1.業務操作分兩階段完成:

接入TCC前,業務操作只需要一步就能完成,但是在接入TCC之後,需要考慮如何將其分成2階段完成,把資源的檢查和預留放在一階段的Try操作中進行,把真正的業務操作的執行放在二階段的Confirm操作中進行;
TCC服務要保證第一階段Try操作成功之後,二階段Confirm操作一定能成功;

2.允許空回滾;

事務協調器在調用TCC服務的一階段Try操作時,可能會出現因為丟包而導致的網路超時,此時事務協調器會觸發二階段回滾,調用TCC服務的Cancel操作;
TCC服務在未收到Try請求的情況下收到Cancel請求,這種場景被稱為空回滾;TCC服務在實現時應當允許空回滾的執行;

3.防懸掛控制;

事務協調器在調用TCC服務的一階段Try操作時,可能會出現因網路擁堵而導致的超時,此時事務協調器會觸發二階段回滾,調用TCC服務的Cancel操作;在此之後,擁堵在網路上的一階段Try數據包被TCC服務收到,出現了二階段Cancel請求比一階段Try請求先執行的情況;
用戶在實現TCC服務時,應當允許空回滾,但是要拒絕執行空回滾之後到來的一階段Try請求;

4.冪等控制:

無論是網路數據包重傳,還是異常事務的補償執行,都會導致TCC服務的Try、Confirm或者Cancel操作被重覆執行;用戶在實現TCC服務時,需要考慮冪等控制,即Try、Confirm、Cancel 執行次和執行多次的業務結果是一樣的;

5.業務數據可見性控制;

TCC服務的一階段Try操作會做資源的預留,在二階段操作執行之前,如果其他事務需要讀取被預留的資源數據,那麼處於中間狀態的業務數據該如何向用戶展示,需要業務在實現時考慮清楚;通常的設計原則是“寧可不展示、少展示,也不多展示、錯展示”;

6.業務數據併發訪問控制;

TCC服務的一階段Try操作預留資源之後,在二階段操作執行之前,預留的資源都不會被釋放;如果此時其他分散式事務修改這些業務資源,會出現分散式事務的併發問題;
用戶在實現TCC服務時,需要考慮業務數據的併發控制,儘量將邏輯鎖粒度降到最低,以最大限度的提高分散式事務的併發性;

6 Hmily

Hmily (How much I love you)
高性能分散式事務tcc開源框架。基於java語言來開發(JDK1.8),支持dubbo,springcloud,motan等rpc框架進行分散式事務。

框架特性

  • 支持嵌套事務(Nested transaction support).
  • 採用disruptor框架進行事務日誌的非同步讀寫,與RPC框架的性能毫無差別。
  • 支持SpringBoot-starter 項目啟動,使用簡單。
  • RPC框架支持 : dubbo,motan,springcloud。
  • 本地事務存儲支持 : redis,mongodb,zookeeper,file,mysql。
  • 事務日誌序列化支持 :java,hessian,kryo,protostuff。
  • 採用Aspect AOP 切麵思想與Spring無縫集成,天然支持集群。
  • 內置經典的分散式事務場景demo工程,並有swagger-ui可視化界面可以快速體驗。

6.1 Hmily原理及流程圖

原理圖:

流程圖:

7 參考文獻

作者:京東物流 宋樂

來源:京東雲開發者社區 自猿其說Tech 轉載請註明來源


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

-Advertisement-
Play Games
更多相關文章
  • 記錄下在開發中經常用到的類型轉換 /// <summary> /// 轉換擴展類 /// </summary> public static partial class Extensions { #region 轉換為long /// <summary> /// 將object轉換為long,若轉換失 ...
  • 基礎說明 本文根據 RFC4226 和 RFC6238 文檔,詳細的介紹 HOTP 和 TOTP 演算法的原理和實現。 兩步驗證已經被廣泛應用於各種互聯網應用當中,用來提供安全性。對於如何使用兩步驗證,大家並不陌生,無非是開啟兩步驗證,然後出現一個二維碼,使用支持兩步驗證的移動應用比如 Google ...
  • 關於HelixToolkit-這個3D呈現的交互處理推薦使用,因為功能比較強大 一個開源3D庫,根據MIT許可證獲得許可。MIT許可證非常寬鬆,允許在專有軟體中使用。該庫基於 .NET,目前專註於 WPF 平臺。 HelixToolkit是.NET Framework的一個開源3D圖形庫,它主要用於 ...
  • 需求:格式為exp的文件,具有json結構,替換掉其中某些數據 解決方法:讀取excel,用npoi讀取指定內容,在exp中找到特定結構,然後替換 讀取excel文件 讀取其他格式的文件也是用此方法 public void OpenExcel() { Microsoft.Win32.OpenFile ...
  • 我們在調試Web頁面時,期望能使用80埠調試(比如本博客站點的每篇博客,我在發佈之前,均需要在我的Mac電腦進行博客內容和樣式的調試和校驗)。而Mac電腦的80埠預設被系統Apache服務占用,下麵分享我常用的2種使用80埠調試Web站點頁面的辦法…… ...
  • 【學習課程】:【【小白入門 通俗易懂】2021韓順平 一周學會Linux】 https://www.bilibili.com/video/BV1Sv411r7vd/?p=14&share_source=copy_web&vd_source=2c07d62293f5003c919b2df9b2e054 ...
  • 在Linux系統中,測試硬碟的性能一般使用fio工具實現,fio是Flexible I/O Tester的縮寫。是一個常受歡迎的、用於測試存儲性能的工具,而且還可以模擬多種不同的I/O模式和工作負載。 一般我們要測試一塊硬碟的性能,一般需要進行隨機寫入測試、隨機讀取測試、順序寫入測試、順序讀取測試和 ...
  • 本章介紹了MongoDB複製集的配置和使用方法,如何初始化和添加節點到複製集,驗證主節點的寫入和從節點的讀取功能。瞭解如何查詢複製集的狀態,包括成員的健康狀況、同步信息和角色等。最後,我們介紹瞭如何配置複製集的安全認證,包括創建用戶和生成keyFile文件,並演示了使用認證信息連接複製集的方式。通過... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...