深入理解「分布式事務」

2021-01-10 計算機java編程

如果一個事務調用了不同伺服器上的操作,那麼它就成為了一個分布式事務。

考慮下面一種場景:當你發了工資之後,把你的當月工資1024從支付寶轉到了餘額寶。

如果在支付寶帳戶扣除1024之後,餘額寶系統掛掉了,餘額寶的帳戶並沒有增加1024,這時候就出現了數據不一致的情況。

在很多系統中都能找到上述情況的影子:

在下單的時候,需要在訂單表中插入一條數據,然後把庫存減去一在搜索的時候如果點擊了廣告,需要先記錄該點擊事件,然後通知商家系統扣除廣告費在一個分布式事務結束的時候,事務的原子特性要求所有參與該事務的伺服器必須全部提交或全部放棄該事務。為了實現這一點,其中一個伺服器承擔了協調者(coordinater)的角色,由它來保證所有的伺服器獲得相同的結果。

協調者(coordinater)的工作方式取決於它選用的協議,「兩階段提交」是分布式事務最常用的協議。

1、two-phase commit protocol

兩階段提交協議(two-phase commit protocol)的設計出發點是允許任何一個參與者自行放棄它自己的那部分事務。由於事務原子性的要求,如果部分事務被放棄,那麼整個分布式事務也必須被放棄。

在該協議的第一個階段,每個參與者投票表決該事務是放棄還是提交,一旦參與者要求提交事務,那麼就不允許放棄該事務。因此,在一個參與者要求提交事務之前,它必須保證最終能夠執行分布式事務中自己的那部分,即使該參與者出現故障而被中途替換掉。

一個事務的參與者如果最終能提交事務,那麼可以說參與者處於事務的準備好(prepared)狀態。為了保證能夠提交,每個參與者必須將事務中所有發生改變的對象以及自身的狀態(prepared)保存到持久性存儲中。

在該協議的第二個階段,事務的每個參與者執行最終統一的決定。如果任何一個參與者投票放棄事務,那麼最終的決定是放棄事務。如果所有的參與者都投票提交事務,那麼最終的決定是提交事務。

問題在於,要保證每個參與者都投票,並且達成一個共同的決定。在無故障時,該協議相當簡單。但是,協議必須在出現各種故障(例如伺服器崩潰,消息丟失或服務暫時無法通信)時能夠正常工作。

2、兩階段提交的實現

為了實現兩階段提交協議,分布式事務中的協調者和參與者通常按照下面的接口進行通信:

canCommit(trans) ?協調者詢問參與者是否可以提交事務,參與者回復自己的投票結果。

doCommit(trans)協調者告訴參與者提交它的那部分事務。

doAbort(trans)協調者告訴參與者放棄它的那部分事務。

haveCommitted(trans, participant)參與者用該操作向協調者確認它提交了事務。

getDecision(trans) ?當參與者在投Yes票後一段時間內未收到應答時,參與者用該操作向協調者詢問事務的投票表決結果。該操作用於從伺服器崩潰或從消息延遲中恢復。

階段一(投票階段):1)協調者向分布式事務的所有參與者發送canCommit?請求2)當參與者收到canCommit請求後,它向協調者回復自己的投票(Yes/No)。 在投Yes票之前,它在持久性存儲中保存所有對象,準備提交。如果投No票,參與者立即放棄。階段二(提交階段):1)協調者收集所有的投票(包括它自己的投票)。 a)如果不存在故障並且所有的投票都是Yes時,那麼協調者將決定提交事務並向所有參與者發送doCommit 請求 b)否則,協調者決定放棄該事務,並向所有投Yes票的參與者發送doAbort請求2)投Yes票的等待者等待協調者發送的doCommit或者doAbort請求。一旦參與者接收到任何一種請求消息, 它將根據該請求放棄或者提交事務。如果請求是提交事務,那麼他還要向協調者發送一個haveCommitted 來確認事務已經提交

3、分布式事務的故障模型

在分布式事務中執行的過程中,可能出現磁碟故障,進程崩潰以及消息的丟失,超時等。

兩階段提交是一種達成共識的協議,在該系統中,如果進程崩潰,那麼是不可能達成共識的。但是,兩階段提交卻是在這些條件下達成了共識,這是由於進程的崩潰被屏蔽,崩潰的進程被一個新的進程取代,新進程的狀態根據持久性存儲中保存的信息和其他進程擁有的信息來設定。

3.1、故障模型

Lampson提出過一個分布式事務的故障模型,包括了硬碟故障、伺服器故障以及通信故障。該故障模型聲稱:可以保證算法在出現故障時正確工作,但是對於不可預見的災難性故障則不能正確處理。儘管會出現錯誤,但是可以在發生不正確行為之前發現並處理這些錯誤。Lampson的故障模型包括以下故障:

對持久性存儲的寫操作可能發生故障(或因為寫操作無效或因為寫入錯誤的值)。例如,將數據寫到錯誤的磁碟塊被認為是災難性故障。文件存儲可能損壞。在持久性存儲中讀數據時可根據校驗和來判斷數據塊是否損壞。伺服器可能偶爾崩潰。當一個崩潰的伺服器由一個新進程取代後,它的可變內存被重置,崩潰之前的數據均丟失。此後新進程執行一個可恢復過程,根據持久存儲中的信息以及從其他進程獲得的信息設置對象的值,包括兩階段提交協議有關對象的值。當一個處理器出現故障時,伺服器也會崩潰,這樣它就不會發送錯誤的信息或將錯誤的值寫入持久存儲,即它不會產生隨機故障。伺服器崩潰可能出現在任何時候,特別是在恢復時也可能出現。消息傳遞可能有任意長的延遲。消息可能丟失、重複或者損壞。接收方(通過校驗和)能夠檢測到受損消息。未發現的受損消息和偽造的消息可能會導致災難性故障。利用這個關於持久性存儲、處理器和通信的故障模型能夠設計出一個可靠系統,該系統的組件可對付任何單一故障,並提供一個簡單的故障模型。特別是,可靠存儲(stable storage)可以在出現一個write操作故障或者進程崩潰的情況下提供原子寫操作。它是通過將每一個數據塊複製到兩個磁碟上實現的。此時一個write操作用於兩個磁碟塊,在一個磁碟出現故障的前提下,另一個好的磁碟也可以提供正確數據。可靠處理器(stable processor)使用可靠存儲,用於在崩潰之後恢復對象。可通過可靠的遠程過程調用機制來屏蔽通信錯誤。

3.2、兩階段提交協議的超時

在兩階段協議的不同階段,協調者或參與者都會遇到這種場景:不能處理它的那部分協議,直到接收到下一個請求或應答為止。

首先考慮這樣的情形:某個投票者投Yes票並等待協調者發回最終決定,即告訴它是提交事務還是放棄事務。這樣參與者的結果是不確定(uncertain)的,它在協調者處得到投票結果之前不能進行進一步處理。參與者不能單方面決定下一步做什麼,同時該事務使用的對象也不能釋放以用於其他事物。參與者向協調者發出getDecision請求來獲取事務的結果,直到收到應答時,才能進入兩階段協議的第二階段。

同理,如果協調者發生故障,那麼參與者將不能獲得協定,直到協調者被替代為止,這可能導致不確定狀態的參與者長時間的延遲。

不依賴協調者獲取最終決定的方法是通過參與者協作來獲得決定。這種策略的優點是可以在協調者出故障時使用。(在本篇文章中我們不討論這種方式)

4、兩階段提交的故障處理

當參與者發生故障的時候:

當協調者發生故障的時候:

5、兩階段提交的性能

假設一切運轉正常,即協調者參與者不出現故障,通信也正常時,有N個參與者的兩階段提交協議需要N個canCommit消息和應答,然後再有N個doCommit消息。這樣消息開銷和3N成正比,時間開銷是3次消息往返。由於協議在沒有haveCommitted消息時仍可以正常運作(它們的作用只是通知伺服器刪除過時的協調者消息),因此在估計協議開銷上,不將haveCommitted消息計算在內。

在最壞的情況下,兩階段提交協議在執行過程中可能出現任意多次伺服器和通信故障。儘管協議不能指定協議完成的時間限制,但它能正確處理連續故障(服務崩潰或者消息丟失),並保證最終完成。

6、使用消息隊列來避免分布式事務

5.1、消息隊列

由於分布式事務存在嚴重的性能問題,在設計高並發服務的時候,往往通過其他途徑來解決數據一致性問題。

舉例來講,你在北京很有名的姚記炒肝點了炒肝並付了錢後,他們並不會直接把你點的炒肝給你,而是給你一張小票,然後讓你拿著小票到出貨區排隊去取。為什麼他們要將付錢和取貨兩個動作分開呢?原因很多,其中一個很重要的原因是為了使他們接待能力增強(並發量更高)。

還是回到我們的問題,只要這張小票在,你最終是能拿到炒肝的。同理轉帳服務也是如此,當支付寶帳戶扣除1萬後,我們只要生成一個憑證(消息)即可,這個憑證(消息)上寫著「讓餘額寶帳戶增加 1萬」,只要這個憑證(消息)能可靠保存,我們最終是可以拿著這個憑證(消息)讓餘額寶帳戶增加1萬的,即我們能依靠這個憑證(消息)完成最終一致性。

這樣我們上述的轉帳就變成了如下過程:

支付寶在扣款事務提交之前,向消息隊列發送消息。此時的消息隊列只記錄消息,而並沒有將消息發往餘額寶。當支付寶扣款事務提交成功,向消息隊列發送確認。在得到確認的指令後,消息隊列向該消息發往餘額寶。當支付寶扣款事務提交失敗,向消息隊列發送取消。在得到取消的指令後,消息隊列取消該消息,該消息將不會被發送。對於那麼未確認的消息,需要消息隊列去支付寶系統查詢這個消息的狀態,並進行更新。(因為支付寶可能在扣款事務提交成功後掛掉,此時消息的狀態未被更新為:「確認發送「。從而導致消息不能被發送。5.2、重複投遞

還有一個嚴重的問題是消息重複投遞,以我們支付寶轉帳到餘額寶為例,如果相同的消息被重複投遞兩次,那麼我們餘額寶帳戶將會增加2萬而不是1萬了。

我們將在後續的文章討論消息隊列的兩個問題:

Exactly-once deliveryGuaranteed order of messages

相關焦點

  • 如何系統性地學習分布式系統?
    本文的緣起是回答知乎圓桌會議「分布式系統之美」的問題「如何系統性地學習分布式系統?」,後面稍微整理了一下,形成了這一篇文章(知乎 ID:kylin)。學習一個知識之前,我覺得比較好的方式是先理解它的來龍去脈:即這個知識產生的過程,它解決了什麼問題,它是怎麼樣解決的,還有它引入了哪些新的問題(沒有銀彈),這樣我們才能比較好的抓到它的脈絡和關鍵點,不會一開始就迷失在細節中。
  • 女朋友問敖丙:什麼是分布式事務?
    本文轉載自微信公眾號「三太子敖丙」,作者三太子敖丙。轉載本文請聯繫三太子敖丙公眾號。不過暖男為了保證文章的完整性確保所有人都聽得懂,我還是得先說說 ACID,然後再來介紹下什麼是分布式事務和常見的分布式事務包括 2PC、3PC、TCC、本地消息表、消息事務、最大努力通知。事務嚴格意義上的事務實現應該是具備原子性、一致性、隔離性和持久性,簡稱 ACID。
  • 「技術貼」微服務中臺技術解析之分布式事務方案和實踐
    隨著軟體系統從單體應用邁向微服務架構以及資料庫選型去中心化、異構化的趨勢,傳統的ACID事務在分布式系統上能否延續,如何落地,有哪些注意事項?本文將圍繞分布式事務這一技術議題,介紹FreeWheel核心業務系統在相關領域的業務需求、技術決策和線上實踐。
  • 深入解析:分布式系統的事務處理經典問題及模型
    Paxos 算法解決的問題是在一個可能發生上述異常的分布式系統中如何就某個值達成一致,保證不論發生以上任何異常,都不會破壞決議的一致性。一個典型的場景是,在一個分布式資料庫系統中,如果各節點的初始狀態一致,每個節點都執行相同的操作序列,那麼他們最後能得到一個一致的狀態。為保證每個節點執行相同的命令序列,需要在每一條指令上執行一個「一致性算法」以保證每個節點看到的指令一致。
  • 分布式事務實現-Spanner
    所有事務的讀寫都加鎖可以解決這個問題,缺點是性能較差。特別是對於一些workload中只讀事務佔比較大的系統來說不可接受。為了讓只讀事務不加任何鎖,需要引入多版本。在單機系統中,維護一個遞增的時間戳作為版本號很好辦。分布式系統中,機器和機器之間的時鐘有誤差,並且誤差範圍不確定,帶來的問題就是很難判斷事件(在本文,事件指分布式事務版本號)發生的前後關係。
  • 如何選擇分布式事務解決方案?
    阿里妹導讀:分布式事務中涉及的參與者分布在異步網絡中,參與者通過網絡通信來達到分布式一致性,網絡通信不可避免出現失敗、超時的情況,因此分布式事務的實現比本地事務面臨更多的困難。本文歸納總結五種分布式事務解決方案,並剖析其特點。較長,同學們可收藏後再看。文末福利:Java 程式設計師學習清單。
  • Hinton 新作「在線蒸餾」,提升深度學習分布式訓練表現的利器
    最近,為了將這種思想部署在分布式環境中,用以突破如今常常被使用的分布式 SGD(同步和異步形式)的瓶頸,Hinton 團隊又發布了名為「LARGE SCALE DISTRIBUTED NEURAL NETWORK TRAINING THROUGH ONLINE DISTILLATION」(通過在線蒸餾的神經網絡大規模分布式訓練)的論文。
  • Spring全家桶、Dubbo、分布式、消息隊列後端必備全套開源項目
    接入 Dubbo 應用」小節Seata《Dubbo 分布式事務 Seata 入門》 對應 lab-53《Spring Cloud Alibaba 分布式事務 Seata 入門》的「2.AT 方案《Spring Boot 分布式事務 Seata 入門》的「2.
  • 支付核心系統設計:Airbnb的分布式事務方案簡介
    本文詳細論述了Airbnb如何使用分布式事務的相關技術來保證支付系統的數據一致性和性能,十分值得一讀。過去幾年中,Airbnb一直在將其基礎架構遷移到SOA。相比單體應用,SOA提供了許多優勢,例如支持開發人員專業化和加速迭代的能力。然而,這也對計費和支付程序提出了挑戰,因為SOA使維護數據完整性變得更加困難。
  • 分布式事務淺析及簡單實現
    作者:翟飛在分布式系統中,為了保證數據的高可用,通常,我們會將數據保留多個副本(replica),這些副本會放置在不同的物理的機器上。為了對用戶提供正確的 CRUD 等語義,我們需要保證這些放置在不同物理機器上的副本是一致的。分布式事務在現在遍地都是分布式部署的系統中幾乎是必要的。我們先聊一下啥是事務?
  • 微服務 SpringCloud Alibaba Seata處理分布式事務
    一、分布式事務問題什麼是分布式事務?二、Seata簡介1.是什麼Seata 是一款開源的分布式事務解決方案,致力於在微服務架構下提供高性能和簡單易用的分布式事務服務。官網地址:http://seata.io/zh-cn/2.主要功能一個典型的分布式事務過程分布式事務處理過程:一ID+三組件模型
  • 分布式事務:螞蟻金服核心金融場景下的演進
    在分布式事務、資料庫高性能/高可靠架構、資料庫內核等領域有較為深入的研究和豐富的工程實踐。  正文:  隨著網際網路技術快速發展,數據規模增大,分布式系統越來越普及,採用分布式資料庫或者跨多個資料庫的應用在中大規模企業普遍存在,而由於網絡、機器等不可靠因素,數據不一致問題很容易出現。
  • 果味財經「Star Time」:萬物互聯,物聯網分布式新物語
    果味財經「Star time」168期,果味財經聯合「新銳人氣資產交易平臺AladdinEX」,舉辦主題為「萬物互聯:物聯網分布式新物語」AMA,嘉賓是物聯網區塊鏈巨頭MatchX.io創始人CEO 胡莘。MXC CEO胡莘,畢業於柏林工業大學,從事物聯網和網絡架構行業,獲得CES 2016最佳創新獎,開創LPWAN區塊鏈新研究方向。
  • 後端程式設計師必備:分布式事務基礎篇
    隔離性:通過鎖以及MVCC,使事務相互隔離開。 一致性:通過回滾、恢復,以及並發情況下的隔離性,從而實現一致性。分布式事務分布式事務: 就是指事務的參與者、支持事務的伺服器、資源伺服器以及事務管理器分別位於不同的分布式系統的不同節點之上。
  • 從銀行轉帳失敗到分布式事務:總結與思考
    這個時候,關係型資料庫保證事務的手段,比如加鎖、日誌就行不通了。當然,本文討論的不僅僅是資料庫,也包含分布式存儲、消息隊列,以及任何要保證原子性、持久性的邏輯。  分布式事務的最大挑戰在於CAP,在《CAP理論與MongoDB一致性、可用性的一些思考》一文中有詳細介紹。
  • 分布式事務(一) 兩階段提交及JTA
    分布式事務簡介分布式事務是指會涉及到操作多個資料庫(或者提供事務語義的系統,如JMS)的事務。其實就是將對同一資料庫事務的概念擴大到了對多個資料庫的事務。目的是為了保證分布式系統中事務操作的原子性。分布式事務處理的關鍵是必須有一種方法可以知道事務在任何地方所做的所有動作,提交或回滾事務的決定必須產生統一的結果(全部提交或全部回滾)。
  • 聯合廣場風投:分布式計算平臺優勢是「完整性 Integrity」,而非價格
    」。她主要修正了去年一個判斷:她去年曾認為價格是分布式計算項目與中心化雲服務提供商競爭時最吸引人的賣點,但她現在認為,想要擊敗中心化的提供商,分布式計算平臺的核心競爭力應該是在為開發人員提供完整性Integrity方面。「提供完整性Integrity」確實是分布式系統不可替代的優勢。
  • 5種分布式事務解決方案優缺點對比
    背景分布式事務是企業集成中的一個技術難點,也是每一個分布式系統架構中都會涉及到的一個東西,特別是在微服務架構中,幾乎可以說是無法避免。04 本地消息表(消息隊列)其核心思想是將分布式事務拆分成本地事務進行處理。方案通過在消費者額外新建事務消息表,消費者處理業務和記錄事務消息在本地事務中完成,輪詢事務消息表的數據發送事務消息,提供者基於消息中間件消費事務消息表中的事務。
  • 純乾貨|細說分布式事務兩階段提交
    作者:旺德事務的概念在這篇文章中描述過,在分布式系統中,讀寫位於多個節點的數據,如果依舊想保證ACID特性,就必須實現分布式事務。而其實現關鍵則是適當的提交協議,目前最簡潔,且使用最廣泛的無疑是兩階段提交協議(2PC)。1.實現分布式事務關鍵組件單機系統通過事務管理器(transaction manager,TM)實現本地事務。
  • 億級流量架構之分布式事務思路及方法
    分布式事務以及分布式鎖是分布式中難點,分布式事務一篇文章可能寫不完,