後端程序員必備:分佈式事務基礎篇

前言

最近看了幾篇有關於分佈式事務的博文,作一下筆記。哈哈~程序員

後端程序員必備:分佈式事務基礎篇

數據庫事務

數據庫事務(簡稱:事務),是數據庫管理系統執行過程當中的一個邏輯單位,由一個有限的數據庫操做序列構成,這些操做要麼所有執行,要麼所有不執行,是一個不可分割的工做單位。sql

數據庫事務的幾個典型特性:原子性(Atomicity )、一致性( Consistency )、隔離性( Isolation)和持久性(Durabilily),簡稱就是ACID。數據庫

後端程序員必備:分佈式事務基礎篇

  • 原子性: 事務做爲一個總體被執行,包含在其中的對數據庫的操做要麼所有被執行,要麼都不執行。
  • 一致性: 指在事務開始以前和事務結束之後,數據不會被破壞,假如A帳戶給B帳戶轉10塊錢,無論成功與否,A和B的總金額是不變的。
  • 隔離性: 多個事務併發訪問時,事務之間是相互隔離的,即一個事務不影響其它事務運行效果。簡言之,就是事務之間是進水不犯河水的。
  • 持久性: 表示事務完成之後,該事務對數據庫所做的操做更改,將持久地保存在數據庫之中。

事務的實現原理

本地事務

傳統的單服務器,單關係型數據庫下的事務,就是本地事務。本地事務由資源管理器管理,JDBC事務就是一個很是典型的本地事務。
後端程序員必備:分佈式事務基礎篇
後端

事務日誌

innodb事務日誌包括redo log和undo log。服務器

redo log(重作日誌)

redo log一般是物理日誌,記錄的是數據頁的物理修改,而不是某一行或某幾行修改爲怎樣,它用來恢復提交後的物理數據頁。網絡

undo log(回滾日誌)

undo log是邏輯日誌,和redo log記錄物理日誌的不同。能夠這樣認爲,當delete一條記錄時,undo log中會記錄一條對應的insert記錄,當update一條記錄時,它記錄一條對應相反的update記錄。架構

事務ACID特性的實現思想

  • 原子性:是使用 undo log來實現的,若是事務執行過程當中出錯或者用戶執行了rollback,系統經過undo log日誌返回事務開始的狀態。
  • 持久性:使用 redo log來實現,只要redo log日誌持久化了,當系統崩潰,便可經過redo log把數據恢復。
  • 隔離性:經過鎖以及MVCC,使事務相互隔離開。
  • 一致性:經過回滾、恢復,以及併發狀況下的隔離性,從而實現一致性。

    分佈式事務

分佈式事務: 就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位於不一樣的分佈式系統的不一樣節點之上。簡單來講,分佈式事務指的就是分佈式系統中的事務,它的存在就是爲了保證不一樣數據庫節點的數據一致性。併發

爲何須要分佈式事務?接下來分兩方面闡述:框架

微服務架構下的分佈式事務

隨着互聯網的快速發展,輕盈且功能劃分明確的微服務,登上了歷史舞臺。好比,一個用戶下訂單,購買直播禮物的服務,被拆分紅三個service,分別是金幣服務(coinService),下訂單服務(orderService)、禮物服務(giftService)。這些服務都部署在不一樣的機器上(節點),對應的數據庫(金幣數據庫、訂單數據庫、禮物數據庫)也在不一樣節點上。
後端程序員必備:分佈式事務基礎篇
分佈式

用戶下單購買禮物,禮物數據庫、金幣數據庫、訂單數據庫在不一樣節點上,用本地事務是不能夠的,那麼如何保證不一樣數據庫(節點)上的數據一致性呢?這就須要分佈式事務啦~

分庫分表下的分佈式事務

隨着業務的發展,數據庫的數據日益龐大,超過千萬級別的數據,咱們就須要對它分庫分表(之前公司是用mycat分庫分表,後來用sharding-jdbc)。一分庫,數據又分佈在不一樣節點上啦,好比有的在深圳機房,有的在北京機房~你再想用本地事務去保證,已經無動於衷啦~仍是須要分佈式事務啦。

好比A轉10塊給B,A的帳戶數據是在北京機房,B的帳戶數據是在深圳機房。流程以下:
後端程序員必備:分佈式事務基礎篇

CAP 理論&BASE 理論

學習分佈式事務,固然須要瞭解 CAP 理論和BASE 理論。

CAP理論

CAP理論做爲分佈式系統的基礎理論,指的是在一個分佈式系統中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),這三個要素最多隻能同時實現兩點。
後端程序員必備:分佈式事務基礎篇

一致性(C:Consistency):

一致性是指數據在多個副本之間可否保持一致的特性。例如一個數據在某個分區節點更新以後,在其餘分區節點讀出來的數據也是更新以後的數據。

可用性(A:Availability):

可用性是指系統提供的服務必須一直處於可用的狀態,對於用戶的每個操做請求老是可以在有限的時間內返回結果。這裏的重點是"有限時間內"和"返回結果"。

分區容錯性(P:Partition tolerance):

分佈式系統在遇到任何網絡分區故障的時候,仍然須要可以保證對外提供知足一致性和可用性的服務。

選擇 說明
CA 放棄分區容錯性,增強一致性和可用性,其實就是傳統的單機數據庫的選擇
AP 放棄一致性,分區容錯性和可用性,這是不少分佈式系統設計時的選擇
CP 放棄可用性,追求一致性和分區容錯性,網絡問題會直接讓整個系統不可用


BASE 理論

BASE 理論, 是對CAP中AP的一個擴展,對於咱們的業務系統,咱們考慮犧牲一致性來換取系統的可用性和分區容錯性。BASE是Basically Available(基本可用),Soft state(軟狀態),和 Eventually consistent(最終一致性)三個短語的縮寫。

Basically Available

基本可用:經過支持局部故障而不是系統全局故障來實現的。如將用戶分區在 5 個數據庫服務器上,一個用戶數據庫的故障隻影響這臺特定主機那 20% 的用戶,其餘用戶不受影響。

Soft State

軟狀態,狀態能夠有一段時間不一樣步

Eventually Consistent

最終一致,最終數據是一致的就能夠了,而不是時時保持強一致。

分佈式事務的幾種解決方案

分佈式事務解決方案主要有如下這幾種:

  • 2PC(二階段提交)方案
  • TCC(Try、Confirm、Cancel)
  • 本地消息表
  • 最大努力通知
  • Saga事務

    二階段提交方案

二階段提交方案是經常使用的分佈式事務解決方案。事務的提交分爲兩個階段:準備階段和提交執行方案。

二階段提交成功的狀況

準備階段,事務管理器向每一個資源管理器發送準備消息,若是資源管理器的本地事務操做執行成功,則返回成功。

提交執行階段,若是事務管理器收到了全部資源管理器回覆的成功消息,則向每一個資源管理器發送提交消息,RM 根據 TM 的指令執行提交。如圖:
後端程序員必備:分佈式事務基礎篇

二階段提交失敗的狀況

準備階段,事務管理器向每一個資源管理器發送準備消息,若是資源管理器的本地事務操做執行成功,則返回成功,若是執行失敗,則返回失敗。

提交執行階段,若是事務管理器收到了任何一個資源管理器失敗的消息,則向每一個資源管理器發送回滾消息。資源管理器根據事務管理器的指令回滾本地事務操做,釋放全部事務處理過程當中使用的鎖資源。

後端程序員必備:分佈式事務基礎篇

二階段提交優缺點

2PC方案實現起來簡單,成本較低,可是主要有如下缺點:

  • 單點問題:若是事務管理器出現故障,資源管理器將一直處於鎖定狀態。
  • 性能問題:全部資源管理器在事務提交階段處於同步阻塞狀態,佔用系統資源,一直到提交完成,才釋放資源,容易致使性能瓶頸。
  • 數據一致性問題:若是有的資源管理器收到提交的消息,有的沒收到,那麼會致使數據不一致問題。

TCC(補償機制)

TCC 採用了補償機制,其核心思想是:針對每一個操做,都要註冊一個與其對應的確認和補償(撤銷)操做。

TCC(Try-Confirm-Cancel)模型

TCC(Try-Confirm-Cancel)是經過對業務邏輯的分解來實現分佈式事務。針對一個具體的業務服務,TCC 分佈式事務模型須要業務系統都實現一下三段邏輯:

try階段:嘗試去執行,完成全部業務的一致性檢查,預留必須的業務資源。

Confirm階段:該階段對業務進行確認提交,不作任何檢查,由於try階段已經檢查過了,默認Confirm階段是不會出錯的。

Cancel 階段:若業務執行失敗,則進入該階段,它會釋放try階段佔用的全部業務資源,並回滾Confirm階段執行的全部操做。
後端程序員必備:分佈式事務基礎篇

TCC 分佈式事務模型包括三部分:主業務服務、從業務服務、業務活動管理器。

  • 主業務服務:主業務服務負責發起並完成整個業務活動。
  • 從業務服務:從業務服務是整個業務活動的參與方,實現Try、Confirm、Cancel操做,供主業務服務調用。
  • 業務活動管理器:業務活動管理器管理控制整個業務活動,包括記錄事務狀態,調用從業務服務的 Confirm 操做,調用從業務服務的 Cancel 操做等。
    下面再拿用戶下單購買禮物做爲例子來模擬TCC實現分佈式事務的過程:

假設用戶A餘額爲100金幣,擁有的禮物爲5朵。A花了10個金幣,下訂單,購買10朵玫瑰。餘額、訂單、禮物都在不一樣數據庫。

TCC的Try階段:

  • 生成一條訂單記錄,訂單狀態爲待確認。
  • 將用戶A的帳戶金幣中餘額更新爲90,凍結金幣爲10(預留業務資源)
  • 將用戶的禮物數量爲5,預增長數量爲10。
  • Try成功以後,便進入Confirm階段
  • Try過程發生任何異常,均進入Cancel階段
    後端程序員必備:分佈式事務基礎篇

TCC的Confirm階段:

  • 訂單狀態更新爲已支付
  • 更新用戶餘額爲90,可凍結爲0
  • 用戶禮物數量更新爲15,預增長爲0
  • Confirm過程發生任何異常,均進入Cancel階段
  • Confirm過程執行成功,則該事務結束
    後端程序員必備:分佈式事務基礎篇

TCC的Cancel階段:

  • 修改訂單狀態爲已取消
  • 更新用戶餘額回100
  • 更新用戶禮物數量爲5
    後端程序員必備:分佈式事務基礎篇

TCC優缺點

TCC方案讓應用能夠自定義數據庫操做的粒度,下降了鎖衝突,能夠提高性能,可是也有如下缺點:

  • 應用侵入性強,try、confirm、cancel三個階段都須要業務邏輯實現。
  • 須要根據網絡、系統故障等不一樣失敗緣由實現不一樣的回滾策略,實現難度大,通常藉助TCC開源框架,ByteTCC,TCC-transaction,Himly。

    本地消息表

ebay最初提出本地消息表這個方案,來解決分佈式事務問題。業界目前使用這種方案是比較多的,它的核心思想就是將分佈式事務拆分紅本地事務進行處理。能夠看一下基本的實現流程圖:
後端程序員必備:分佈式事務基礎篇

基本實現思路

發送消息方:

  • 須要有一個消息表,記錄着消息狀態相關信息。
  • 業務數據和消息表在同一個數據庫,即要保證它倆在同一個本地事務。
  • 在本地事務中處理完業務數據和寫消息表操做後,經過寫消息到MQ消息隊列。
  • 消息會發到消息消費方,若是發送失敗,即進行重試。

    消息消費方:

  • 處理消息隊列中的消息,完成本身的業務邏輯。
  • 此時若是本地事務處理成功,則代表已經處理成功了。
  • 若是本地事務處理失敗,那麼就會重試執行。
  • 若是是業務上面的失敗,給消息生產方發送一個業務補償消息,通知進行回滾等操做。

生產方和消費方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發送一遍。若是有靠譜的自動對帳補帳邏輯,這種方案仍是很是實用的。

優勢&缺點:

該方案的優勢是很好地解決了分佈式事務問題,實現了最終一致性。缺點是消息表會耦合到業務系統中。

最大努力通知

什麼是最大通知

最大努力通知也是一種分佈式事務解決方案。下面是企業網銀轉帳一個例子
後端程序員必備:分佈式事務基礎篇

  • 企業網銀系統調用前置接口,跳轉到轉帳頁
  • 企業網銀調用轉帳系統接口
  • 轉帳系統完成轉帳處理,向企業網銀系統發起轉帳結果通知,若通知失敗,則轉帳系統按策略進行重複通知。
  • 企業網銀系統未接收到通知,會主動調用轉帳系統的接口查詢轉帳結果。
  • 轉帳系統會遇到退匯等狀況,會定時回來對帳。
    最大努力通知方案的目標,就是發起通知方經過必定的機制,最大努力將業務處理結果通知到接收方。最大努力通知實現機制以下:
    後端程序員必備:分佈式事務基礎篇

最大努力通知解決方案

要實現最大努力通知,能夠採用MQ的ack機制。

方案

後端程序員必備:分佈式事務基礎篇

  • 1.發起方將通知發給MQ。
  • 2.接收通知方監聽MQ消息。
  • 3.接收通知方收到消息後,處理完業務,迴應ack。
  • 4.接收通知方若沒有迴應ack,則MQ會間隔1min、5min、10min等重複通知。
  • 5.接受通知方可用消息校對接口,保證消息的一致性。
    轉帳業務實現流程圖:
    後端程序員必備:分佈式事務基礎篇
    交互流程以下:


  • 一、用戶請求轉帳系統進行轉帳。
  • 二、轉帳系統完成轉帳,將轉帳結果發給MQ。
  • 三、企業網銀系統監聽MQ,接收轉帳結果通知,若是接收不到消息,MQ會重複發送通知。接收到轉帳結果,更新轉帳狀態。
  • 四、企業網銀系統也能夠主動查詢轉帳系統的轉帳結果查詢接口,更新轉帳狀態。

    Saga事務

Saga事務由普林斯頓大學的Hector Garcia-Molina和Kenneth Salem提出,其核心思想是將長事務拆分爲多個本地短事務,由Saga事務協調器協調,若是正常結束那就正常完成,若是某個步驟失敗,則根據相反順序一次調用補償操做。

saga簡介

  • Saga = Long Live Transaction (LLT,長活事務)
  • LLT = T1 + T2 + T3 + ... + Ti(Ti爲本地短事務)
  • 每一個本地事務Ti 有對應的補償 Ci

    Saga的執行順序

  • 正常狀況:T1 T2 T3 ... Tn
  • 異常狀況:T1 T2 T3 C3 C2 C1

    Saga兩種恢復策略

  • 向後恢復,若是任意本地子事務失敗,補償已完成的事務。如異常狀況的執行順序T1 T2 Ti Ci C2 C1.
  • 向前恢復,即重試失敗的事務,假設最後每一個子事務都會成功。執行順序:T1, T2, ..., Tj(失敗), Tj(重試),..., Tn。

舉個例子,假設用戶下訂單,花10塊錢購買了10多玫瑰,則有

T1=下訂單 ,T2=扣用戶10塊錢,T3=用戶加10朵玫瑰, T4=庫存減10朵玫瑰

C1=取消訂單 ,C2= 給用戶加10塊錢,C3 =用戶減10朵玫瑰, C4=庫存加10朵玫瑰
後端程序員必備:分佈式事務基礎篇

假設事務執行到T4發生異常回滾,在C4的要把玫瑰給庫存加回去的時候,發現用戶的玫瑰都用掉了,這是Saga的一個缺點,因爲事務之間沒有隔離性致使的問題。

能夠經過如下方案解決這個問題:

  • 在應⽤層⾯加⼊邏輯鎖的邏輯。
  • Session層⾯隔離來保證串⾏化操做。
  • 業務層⾯採⽤預先凍結資⾦的⽅式隔離此部分資⾦。
  • 業務操做過程當中經過及時讀取當前狀態的⽅式獲取更新。

參考與感謝

  • 乾貨 | 一篇文章帶你學習分佈式事務
  • 再有人問你分佈式事務,把這篇扔給他
  • 聊聊分佈式事務,再說說解決方案
  • Mysql事務實現原理
  • 詳細分析MySQL事務日誌(redo log和undo log)
  • 《Saga分佈式事務解決⽅案與實踐》
  • 分佈式事務解決方案之最大努力通知

我的公衆號

後端程序員必備:分佈式事務基礎篇

  • 以爲寫得好的小夥伴給個點贊+關注啦,謝謝~
  • 同時很是期待小夥伴們可以關注我公衆號,後面慢慢推出更好的乾貨~嘻嘻
相關文章
相關標籤/搜索