分散式系統一致性保障方案總結

来源:https://www.cnblogs.com/lfs2640666960/archive/2018/07/27/9379017.html
-Advertisement-
Play Games

在互聯網系統中,理想的情況下,肯定是希望系統能夠同時滿足“一致性”、“可用性”和“分區容忍性”。 但是基於熟悉的CAP定律也好,還是BASE理論, 我們知道,在實際情況中是不可能實現的。本文重點來闡述下關於一致性的方案,包括強一致性和最終一致性。 ...


群里經常卧虎藏龍,轉載一篇百度大牛,投稿原創文章,大家交流學習 ,歡迎更多朋友投稿,發佈原創文章和乾貨和大家分享交流。

 

引言

       在互聯網系統中,理想的情況下,肯定是希望系統能夠同時滿足“一致性”、“可用性”和“分區容忍性”。 但是基於熟悉的CAP定律也好,還是BASE理論, 我們知道,在實際情況中是不可能實現的。而在金融領域,一致性是最為關註的特性,任何情況下都必須滿足一致性。關於CAP定律和BASE理論,本文不再介紹,有興趣的同學可以自行百度一下。本文重點來闡述下關於一致性的方案,包括強一致性和最終一致性。 而在互聯網領域, 很多情況下都是犧牲強一致性,來達到高可用性,統往往只需要保證“最終一致性”,只要這個最終時間是在用戶可以接受的範圍內即可。

 

資料庫本地事務

       資料庫事務肯定是強一致性的方案,而且是一致性最簡單的方案,因為一致性是資料庫的事務來保證的,業務層不需要關心細節。比較典型的應用是在返現場景下,針對帶有返現的交易的退款,需要一次性退兩筆交易單,採用的就是通過資料庫本地事務來完成的。具體如下:

 

用戶A花了100元購買商戶B的商品,購買結束後返現給用戶A 2元。 這是兩筆交易,原始交易是100元,返現交易是2元。 那麼發生退款時,需要保證兩筆交易同時都退款。這個就是直接採用資料庫本地事務實現的,即一次退款請求,兩筆交易同時退款。

 

總結: 資料庫事務的優點是簡單,業務層關心的很少。但是對於一個可用性很高的系統來說,所有的業務都揉在資料庫事務執行,會讓事務非常的複雜,不利於系統的擴展和維護。

 

兩階段提交

        除了資料庫能夠保證本地的一致性,對於互聯網系統來說,更多是分散式系統。提到分散式系統,必然提到分散式事務。而分散式事務中,就不得不介紹兩階段提交協議(2pc)。 而在核心系統,兩階段提交的方案主要應用在分散式資料庫NesioDB和交易賬務分離的柔性事務中

       分散式資料庫NesioDB是由百度DBA和百度錢包聯合開發的,支持分散式事務的資料庫,目前已經應用在百度錢包的核心交易業務上,並穩定運行兩年。該資料庫的設計要求是讓使用者能夠像使用單機資料庫一樣的使用分散式資料庫,因此實現的分散式事務,滿足單機事務的ACID原則。關於分散式事務的一致性,採用的就是兩階段提交的方式來實現的,並且滿足分散式事務模型。如下圖所示。

第一階段是準備階段。

 

 

 

 

DTM 通知所有參與事務的各個 RM,給每個 RM 發送 prepare 消息。RM 接收到消息後進入準備階段後,要麼直接返回失敗,要麼創建並執行本地事務,寫本地事務日誌(redo 和 undo 日誌),但是 不提交(此處只保留最後一步耗時最少的提交操作給第二階段執行)。

第二階段是提交/回滾階段。

 

 

 

DTM 收到 RM 準備階段的失敗消息或者獲取 RM 返回消息超時,則直接給 RM 發送回滾(rollback)消息,否則發送提交(commit)消息。RM 根據 TM 的指令執行提交或者回滾,執行完成後釋放所有事務處理過程中使用的鎖(最後階段釋放鎖)。

資料庫層面的兩階段提交,可以用來保證分散式事務的一致性,使得使用者使用分散式事務和單機事務一樣方便。而兩階段提交的另外一種實現,即TCC(Try-Confirm-Cancel), 也就是業務層面的柔性事務。 交易和賬務分離的一致性實現,就是採用這種柔性事務來完成的。首先來說說柔性事務,它涉及 3 個模塊,主業務、從業務 和 活動管理器(協作者)。

下麵這張圖是有關柔性事務一張經典的圖。

 

第一階段:主業務服務分別調用所有從業務服務的 try 操作,併在活動管理器中記錄所有從業務服務。當所有從業務服務 try 成功或者某個從業務服務 try 失敗時,進入第二階段。

第二階段:活動管理器根據第一階段從業務服務的 try 結果來執行 confirm 或 cancel 操作。如果第一階段所有從業務服務都 try 成功,則協作者調用所有從業務服務的 confirm 操作,否則,調用所有從業務服務的 cancel 操作。

在第二階段中,confirm 和 cancel 同樣存在失敗情況,所以需要對這兩種情況做 異常處理以保證數據一致性。

1.  Confirm 失敗:則回滾所有 confirm 操作並執行 cancel 操作。

2.  Cancel 失敗:從業務服務需要提供自動 cancel 機制,以保證 cancel 成功。

如果對應到交易和賬務分離的項目中,流程如下:

第一階段:  主業務服務調用交易和賬務執行try的操作,交易開啟事務,做業務上的判斷和寫入,但是不提交事務。賬務層面做資源的鎖定。

第二階段:  賬務資源鎖定成功,交易提交事務成功,然後發送confirm 給賬務。  如果交易提交失敗,則發送cancel對資源進行釋放。如果在confirm或者cancel出現異常情況下,同樣需要對異常進行處理來保證數據一致性。

 

總結: 這種方式實現難度不算太高,比較適合傳統的單體應用,在同一個方法中存在跨庫操作的情況。

 

回滾機制

     在分散式架構中,功能 X,需要去協調後端的 A、B 甚至更多的原子服務。那麼問題來了,假如 A 和 B 其中一個調用失敗了,那可怎麼辦呢? 這個時候,可以用回滾機制來保證一致性。 該機制應用在錢包配合信貸做的聯合放貸項目中。 該項目中總共有兩個原子操作,如下圖所示。

 

 

兩個原子操作,分別是資金歸集和資金到卡。所謂資金歸集,是將商戶A的錢和商戶B的錢歸集到中間商戶C。而資金到卡,是將中間商戶C的錢,通過銀行系統打入到D用戶的銀行卡。這兩個操作要滿足一致性,即資金歸集成功,然後打款到用戶的卡成功。或者是商戶A和B的錢沒變化,資金到卡失敗。 總而言之,是不允許資金停留在中間商戶C的。

       針對這種情況,通過回滾機制,提供一個強大的回滾操作來實現上述的一致性。比如資金歸集成功,而資金到卡失敗,那麼對歸集的資金操作做回滾處理,也就是資金從中間商戶C分別回到商戶A和B中。

 

總結: 這種方式缺點比較多,通常在複雜場景下是不推薦使用的,除非是非常簡單的場景,非常容易提供回滾,而且依賴的服務也非常少的情況。這種實現方式會造成代碼量龐大,耦合性高。而且非常有局限性,因為有很多的業務是無法很簡單的實現回滾的,如果串列的服務很多,回滾的成本實在太高。

 

本地消息表

       這種實現方式的思路,其實是源於 ebay,後來通過支付寶等公司的佈道,在業內廣泛使用。其基本的設計思想是將遠程分散式事務拆分成一系列的本地事務。如果不考慮性能及設計優雅,藉助關係型資料庫中的表即可實現。本地消息的方式,在應用在錢包非核心業務非同步化改造項目中。該項目當時改造的方案如下:

1.   核心業務實時寫入交易表

2.   非核心業務非實時非同步寫入交易表按照用戶維度的交易查詢表。

交易表是交易維度的,而為了滿足用戶的查詢性能,需要備份複製相同的按照用戶維度的交易查詢表。 從業務屬性上來看,交易表是核心業務,交易查詢表是非核心業務(查詢使用)。而實現上,交易表是核心資料庫,而查詢表則屬於非核心資料庫。 但是, 這兩者需要滿足一致性。 關於這類一致性保障,如果有不丟消息的消息隊列,則很容易解決。萬一沒有這類消息隊列呢? 其實,使用本地消息表,也一樣可以解決。

 

 

如圖所示,是利用本地消息表保持最終一致性的應用。 具體如下:

1.   業務A將本地消息和A業務數據以本地事務的方式寫入DB1;

2.   業務A寫完本地事務後,發送消息給MQ。

3.   MQ推送消息給業務B,業務B執行消息,寫入DB2.

4.   由於MQ不能保證消息不丟,如果消息丟失了,則需要通過業務C,讀取DB1的消息,然後rpc發送給業務B重新執行。

當然,如何判斷DB1的消息已經消費,這個可以通過DB2的事務執行結果來判斷。

 

總結: 上訴的方式是一種非常經典的實現,基本避免了分散式事務,實現了“最終一致性”。但是,關係型資料庫的吞吐量和性能方面存在瓶頸,頻繁的讀寫消息會給資料庫造成壓力。所以,在真正的高併發場景下,該方案也會有瓶頸和限制的。

 

補償機制

       補償機制在分散式系統中,應用最為廣泛。在錢包應用的場景比較多,比如核心收銀台和付款到卡。 核心收銀臺中,當請求銀行扣款,扣款成功後,自身系統掛掉了。這個時候就會有一個後臺程式,我們也稱作補單程式來開始處理這類流程,讓原來中間斷掉的流程繼續走下去。

      一般成熟的系統中,對於級別較高的服務和介面,整體的可用性通常都會很高。如果有些業務由於瞬時的網路故障或調用超時等問題,那麼這種補償機制其實是非常有效的。

 

總結

       本文通過核心系統的幾個具體實際項目,闡述瞭如何保證分散式系統的一致性。每一種方案都有一定的特征和應用場景。 其實分散式系統的事務一致性本身是一個技術難題,目前沒有一種很簡單很完美的方案能夠應對所有場景。具體還是要使用者根據不同的業務場景去抉擇。


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

-Advertisement-
Play Games
更多相關文章
  • 瀏覽器開發者模式發現,使用select2插件後,你看到的下拉框是span,真正的下拉框select是隱藏掉了。 所以要隱藏下拉框應該設置最外面的span隱藏。比如我的設置如下: 同理:設置寬度,也應該設置span。不過一開始在select寫style="width:300px"時,在渲染成selec ...
  • <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <style> *{ margin: 0px; padding: 0px; } #outer{ width: 240px; mar ...
  • /*$http常用的幾個參數 $http服務的設置對象: 1、method 字元串 表示發送的請求類型 get post jsonp等等 2、url 字元串 絕對或者相對的URL,請求的目標 3、params 字元串或對象 會被轉化成查詢字元串加到URL後面,如果不是字元串會被JSON序列化 4、d ...
  • RovingUI是個人在開發小程式過程中將用到的組件集合而成的一個UI庫,包含一些基本通用組件(按鈕、柵格、通用樣式、徽標、通知和麵包屑)。 源起得歸於我在開發中沒有找到現成的堆棧式提醒框(比如antd裡面的Notification),於是就自己寫了一個。發現效果還不錯,遂添了幾個通用組件,於是就有 ...
  • 在採用JQuery進行表單非同步提交時,前臺傳入的是json數據格式,後臺controller用map接收,再傳回前臺進行結果判斷時,if-else接收結果()裡面,儘量不要出現“=”,不然判斷語句失效,應該在後臺將一個boolean類型的flag變數存入map中:map.put("flag",tru ...
  • 匿名對象的概念: 匿名對象是指創建對象時,只有創建對象的語句,卻沒有把對象地址值賦值給某個變數。 格式: 創建一個普通對象 創建一個匿名對象 匿名對象的特點: l 創建匿名對象直接使用,沒有變數名。 l 匿名對象在沒有指定其引用變數時,只能使用一次。匿名對象不能被多次使用去調用方法 l 匿名對象可以 ...
  • 1.1 final的概念 final是個修飾符,它可以用來修飾類,類的成員,以及局部變數。不能修飾構造方法。 問題: 繼承的出現提高了代碼的復用性,並方便開發。但隨之也有問題,有些類在描述完之後,不想被繼承,或者有些類中的部分方法功能是固定的,不想讓子類重寫。可是當子類繼承了這些特殊類之後,就可以對 ...
  • static概念 static它是靜態修飾符,一般用來修飾類中的成員。 static特點 1.多個對象共用一個static成員變數。一個對象將static成員變數值修改了,其他對象中的static成員變數值也跟著改變 2.被static修飾的成員可以並且建議通過類名直接訪問。 訪問靜態成員的格式: ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...