分布式事務(wù)

什么是事務(wù)?

發(fā)生錯誤,回滾操作。
要么全部正確執(zhí)行,要么全不執(zhí)行。

事務(wù)四大特性

ACID 原子性Atomicity,一致性Consistency,隔離性Isolation,持久性Durability

  • 原子性:事務(wù)里是一個(gè)不可分割整體,要么一起執(zhí)行,要么一起不執(zhí)行。
  • 一致性:事務(wù)執(zhí)行前后,數(shù)據(jù)庫一致性沒有被破壞。提交事務(wù)沒有中間狀態(tài)。要么提交前,要么提交后。
  • 隔離性:事務(wù)之間互不干擾。
  • 持久性:提交了就永久改變了,不會不生效。

事務(wù)隔離級別


讀未提交 read-uncommitted
  • A還沒提交,B就讀了。若A rollback,B讀到錯誤數(shù)據(jù)(臟讀)。
不可重復(fù)讀/讀提交 read-committed
  • 提交了才能讀
  • A讀,B修改并提交,A再讀變了(不可重復(fù)讀)
可重復(fù)讀 repeatable-read
  • 讀時(shí)不可修改(行鎖)A讀,B不準(zhǔn)改,A再讀完成,B改
  • A讀(范圍),B插入并提交(不修改A鎖的),A再讀,個(gè)數(shù)變了(幻讀)
串行化/可 serializable
  • 讀時(shí)不可增刪改(表鎖)
事務(wù)隔離級別 臟讀 不可重復(fù)讀 幻讀
讀未提交(read-uncommitted) ? ? ?
不可重復(fù)讀(read-committed) ? ? ?
可重復(fù)讀(repeatable-read) ? ? ?
串行化(serializable) ? ? ?

級別越高,執(zhí)行效率就越低。

  • MySQL默認(rèn)可重復(fù)讀
  • Oracle默認(rèn)讀提交,支持read committed 和 serializable。另外還支持read only(只讀,不可修改) 和 read write(默認(rèn))

事務(wù)傳播級別

7種:

傳播級別 描述 上下文存在事務(wù) 上下文不存在事務(wù)
REQUIRED 默認(rèn) 加入事務(wù)中 新建事務(wù)
SUPPORTS 支持 加入事務(wù)中 非事務(wù)方式執(zhí)行
MANDATORY 強(qiáng)制上下文有事務(wù) 加入事務(wù) 拋出異常
REQUIRES_NEW 新事務(wù) 新建事務(wù),掛起上下文事務(wù) 新建事務(wù)
NOT_SUPPORTED 不支持 掛起上下文事務(wù),執(zhí)行當(dāng)前邏輯 新建事務(wù)
NEVER 不可有上下文事務(wù) 拋出runtime異常,強(qiáng)制停止 非事務(wù)方式執(zhí)行
NESTED 嵌套執(zhí)行 子回滾,父不影響;父回滾,子回滾;子先提交,父后提交 新建事務(wù)

一致性解決方案

兩階段提交(2PC),三階段提交(3PC),補(bǔ)償事務(wù)(TCC),消息中間件(MQ異步確保)& 最大努力通知(定期校對)

兩階段提交(2PC)

Prepare、Commit 兩個(gè)階段

準(zhǔn)備階段

1)協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)詢問是否可以執(zhí)行提交操作(vote),并開始等待各參與者節(jié)點(diǎn)的響應(yīng)。
2)參與者節(jié)點(diǎn)執(zhí)行詢問發(fā)起為止的所有事務(wù)操作,并將Undo信息和Redo信息寫入日志。(注意:若成功這里其實(shí)每個(gè)參與者已經(jīng)執(zhí)行了事務(wù)操作)
3)各參與者節(jié)點(diǎn)響應(yīng)協(xié)調(diào)者節(jié)點(diǎn)發(fā)起的詢問。如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行成功,則它返
回一個(gè)”同意”消息;如果參與者節(jié)點(diǎn)的事務(wù)操作實(shí)際執(zhí)行失敗,則它返回一個(gè)”中止”消息。

提交階段
  • 當(dāng)協(xié)調(diào)者節(jié)點(diǎn)從所有參與者節(jié)點(diǎn)獲得的相應(yīng)消息都為”同意”時(shí):
    1)協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出”正式提交(commit)”的請求。
    2)參與者節(jié)點(diǎn)正式完成操作,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源。
    3)參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送”完成”消息。
    4)協(xié)調(diào)者節(jié)點(diǎn)受到所有參與者節(jié)點(diǎn)反饋的”完成”消息后,完成事務(wù)。

  • 如果任一參與者節(jié)點(diǎn)在第一階段返回的響應(yīng)消息為”中止”,或者 協(xié)調(diào)者節(jié)點(diǎn)在第一階段的詢問超時(shí)之前無法獲取所有參與者節(jié)點(diǎn)的響應(yīng)消息時(shí):
    1)協(xié)調(diào)者節(jié)點(diǎn)向所有參與者節(jié)點(diǎn)發(fā)出”回滾操作(rollback)”的請求。
    2)參與者節(jié)點(diǎn)利用之前寫入的Undo信息執(zhí)行回滾,并釋放在整個(gè)事務(wù)期間內(nèi)占用的資源。
    3)參與者節(jié)點(diǎn)向協(xié)調(diào)者節(jié)點(diǎn)發(fā)送”回滾完成”消息。
    4)協(xié)調(diào)者節(jié)點(diǎn)受到所有參與者節(jié)點(diǎn)反饋的”回滾完成”消息后,取消事務(wù)。

2PC缺點(diǎn):
  1. 同步阻塞問題。執(zhí)行過程中,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的。當(dāng)參與者占有公共資源時(shí),其他第三方節(jié)點(diǎn)訪問公共資源不得不處于阻塞狀態(tài)。
  2. 單點(diǎn)故障。由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障。參與者會一直阻塞下去。尤其在第二階段,協(xié)調(diào)者發(fā)生故障,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中,而無法繼續(xù)完成事務(wù)操作。(如果是協(xié)調(diào)者掛掉,可以重新選舉一個(gè)協(xié)調(diào)者,但是無法解決因?yàn)閰f(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問題)
  3. 數(shù)據(jù)不一致。在二階段提交的階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請求之后,發(fā)生了局部網(wǎng)絡(luò)異常或者在發(fā)送commit請求過程中協(xié)調(diào)者發(fā)生了故障,這回導(dǎo)致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之后就會執(zhí)行commit操作。但是其他部分未接到commit請求的機(jī)器則無法執(zhí)行事務(wù)提交。于是整個(gè)分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象。
  4. 二階段無法解決的問題:協(xié)調(diào)者再發(fā)出commit消息之后宕機(jī),而唯一接收到這條消息的參與者同時(shí)也宕機(jī)了。那么即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者,這條事務(wù)的狀態(tài)也是不確定的,沒人知道事務(wù)是否被已經(jīng)提交。

三階段提交(3PC)

CanCommit、PreCommit、DoCommit三個(gè)階段

  1. 引入超時(shí)機(jī)制。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制。
  2. 在第一階段和第二階段中插入一個(gè)準(zhǔn)備階段。保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的。
CanCommit階段

協(xié)調(diào)者向參與者發(fā)送commit請求,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)。

  1. 事務(wù)詢問 協(xié)調(diào)者向參與者發(fā)送CanCommit請求。詢問是否可以執(zhí)行事務(wù)提交操作。然后開始等待參與者的響應(yīng)。

  2. 響應(yīng)反饋 參與者接到CanCommit請求之后,正常情況下,如果其自身認(rèn)為可以順利執(zhí)行事務(wù),則返回Yes響應(yīng),并進(jìn)入預(yù)備狀態(tài)。否則反饋No

PreCommit階段
  • 假如協(xié)調(diào)者從所有的參與者獲得的反饋都是Yes響應(yīng),那么就會執(zhí)行事務(wù)的預(yù)執(zhí)行。
  1. 發(fā)送預(yù)提交請求 協(xié)調(diào)者向參與者發(fā)送PreCommit請求,并進(jìn)入Prepared階段。
  2. 事務(wù)預(yù)提交 參與者接收到PreCommit請求后,會執(zhí)行事務(wù)操作,并將undo和redo信息記錄到事務(wù)日志中。
  3. 響應(yīng)反饋 如果參與者成功的執(zhí)行了事務(wù)操作,則返回ACK響應(yīng),同時(shí)開始等待最終指令。
  • 假如有任何一個(gè)參與者向協(xié)調(diào)者發(fā)送了No響應(yīng),或者等待超時(shí)之后,協(xié)調(diào)者都沒有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷。
  1. 發(fā)送中斷請求 協(xié)調(diào)者向所有參與者發(fā)送abort請求。
  2. 中斷事務(wù) 參與者收到來自協(xié)調(diào)者的abort請求之后(或超時(shí)之后,仍未收到協(xié)調(diào)者的請求),執(zhí)行事務(wù)的中斷。

相對于2PC,3PC主要解決的單點(diǎn)故障問題,并減少阻塞,因?yàn)橐坏﹨⑴c者無法及時(shí)收到來自協(xié)調(diào)者的信息之后,他會默認(rèn)執(zhí)行commit。而不會一直持有事務(wù)資源并處于阻塞狀態(tài)。但是這種機(jī)制也會導(dǎo)致數(shù)據(jù)一致性問題,因?yàn)椋捎诰W(wǎng)絡(luò)原因,協(xié)調(diào)者發(fā)送的abort響應(yīng)沒有及時(shí)被參與者接收到,那么參與者在等待超時(shí)之后執(zhí)行了commit操作。這樣就和其他接到abort命令并執(zhí)行回滾的參與者之間存在數(shù)據(jù)不一致的情況。


補(bǔ)償事務(wù)(TCC)

基于業(yè)務(wù)層面的事務(wù)定義。
鎖粒度完全由業(yè)務(wù)自己控制。
本質(zhì)是一種補(bǔ)償?shù)乃悸贰?br> 把事務(wù)運(yùn)行過程分成 Try、Confirm / Cancel 兩個(gè)階段

Try :嘗試執(zhí)行業(yè)務(wù)
  • 完成所有業(yè)務(wù)檢查( 一致性 )
  • 預(yù)留必須業(yè)務(wù)資源( 準(zhǔn)隔離性 )
Confirm / Cancel 階段:
  • Confirm :
    真正執(zhí)行業(yè)務(wù)
    不做任務(wù)業(yè)務(wù)檢查
    Confirm 操作滿足冪等性
  • Cancel :
    釋放 Try 階段預(yù)留的業(yè)務(wù)資源
    Cancel 操作滿足冪等性
    Confirm 與 Cancel 互斥

本地消息表

將需要分布式處理的任務(wù)通過消息日志的方式來異步執(zhí)行。消息日志可以存儲到本地文本、數(shù)據(jù)庫或消息隊(duì)列,再通過業(yè)務(wù)規(guī)則自動或人工發(fā)起重試。
本地消息表記錄狀態(tài),定時(shí)掃描,重新發(fā)送失敗的消息


消息中間件(MQ異步確保) 最大努力通知(定期校對)

RocketMQ

  • 業(yè)務(wù)方法內(nèi)要向消息隊(duì)列提交兩次請求,一次發(fā)送消息和一次確認(rèn)消息。如果確認(rèn)消息發(fā)送失敗了RocketMQ會定期掃描消息集群中的事務(wù)消息,這時(shí)候發(fā)現(xiàn)了Prepared消息,它會向消息發(fā)送者確認(rèn),所以生產(chǎn)方需要實(shí)現(xiàn)一個(gè)check接口,RocketMQ會根據(jù)發(fā)送端設(shè)置的策略來決定是回滾還是繼續(xù)發(fā)送確認(rèn)消息。這樣就保證了消息發(fā)送與本地事務(wù)同時(shí)成功或同時(shí)失敗。

  • 系統(tǒng)A除了實(shí)現(xiàn)正常的業(yè)務(wù)流程外,還需提供一個(gè)事務(wù)詢問的接口,供消息中間件調(diào)用。當(dāng)消息中間件收到一條事務(wù)型消息后便開始計(jì)時(shí),如果到了超時(shí)時(shí)間也沒收到系統(tǒng)A發(fā)來的Commit或Rollback指令的話,就會主動調(diào)用系統(tǒng)A提供的事務(wù)詢問接口詢問該系統(tǒng)目前的狀態(tài)。該接口會返回三種結(jié)果:
    提交:將該消息投遞給系統(tǒng)B。
    回滾:直接將條消息丟棄。
    處理中:繼續(xù)等待。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容