在微服務架構中兄渺,隨著服務的逐步拆分趋厉,數(shù)據(jù)庫私有已經(jīng)成為共識寨闹。
隨著用戶訪問量的逐漸上漲,數(shù)據(jù)庫甚至是服務的分片君账、分區(qū)繁堡、水平拆分、垂直拆分已經(jīng)逐漸成為較為常用的提升瓶頸的解決方案乡数,因此越來越多的原子操作變成了跨庫甚至是跨服務的事務操作椭蹄。
例如一個電商應用,用戶下單后需要操作訂單表瞳脓,庫存表和用戶表塑娇,如果這三個表是在同一個數(shù)據(jù)庫實例中,可以放在一個事務中來保持一致性:
start transaction
insert into orders...
update inventories...
update users...
commit
如果這三個表是在三個不同的數(shù)據(jù)庫實例中劫侧,又如何保證一致性呢埋酬?
分布式事務
多個副本 replica,存在不同的物理機器上烧栋。
在分布式數(shù)據(jù)庫上写妥,提交或回滾事務的決定必須統(tǒng)一。即要么一起提交审姓,要么一起回滾珍特。
2階提交 Two Phase Commitment
準備階段 Prepare
- 協(xié)調(diào)者(事務管理器)向所有參與者詢問是否可以執(zhí)行提交操作 vote,并等待各個參與者的相應魔吐。
- 參與者執(zhí)行所有事務操作扎筒,并寫入 redo log 和 undo log。
- 參與者相應詢問:
- 若實際執(zhí)行成功酬姆,返回 “同意”
- 若實際執(zhí)行失敗嗜桌,返回 “中止”
提交階段
-
若所有參與者都返回 “同意”:
- 協(xié)調(diào)者(事務管理器)向所有參與者發(fā)出 “正式提交” 的請求。
- 參與者收到請求后辞色,正式提交骨宠。
- 參與者返回 “完成”。
- 協(xié)調(diào)者(事務管理器)收到所有的 “完成” 消息后,完成事務层亿。
-
若有任何一個參與者返回 “中止”桦卒,或詢問超時(即有部分參與者沒有相應):
- 協(xié)調(diào)者(事務管理器)向所有參與者發(fā)出 “回滾” 的請求。
- 參與者收到請求后匿又,利用 undo log 進行回滾方灾。
- 參與者返回 “回滾完成”。
- 協(xié)調(diào)者(事務管理器)收到所有的 “回滾完成” 消息后琳省,取消事務迎吵。
缺點:
- 所有參與者都是事務阻塞的躲撰。
- 單點故障针贬。協(xié)調(diào)者一旦故障,則無法進行拢蛋。
- 數(shù)據(jù)不一致桦他。在第二個階段,協(xié)調(diào)者(事務管理器)向所有參與者發(fā)出 “正式提交” 或者 “回滾” 的請求谆棱,部分參與者可能由于網(wǎng)絡問題收不到快压。從而導致有的參與者提交,有的沒有提交垃瞧。
分布式系統(tǒng)中的所有通信均存在著三種狀態(tài):成功蔫劣,失敗,超時个从。其中脉幢,超時狀態(tài)的存在是我們在設計分布式系統(tǒng)時所面對的永遠的痛,2PC 同樣存在問題嗦锐,尤其是在發(fā)送完可以提交的指令后嫌松,參與者在沒有收到提交或者回滾的指令時,面對已經(jīng)上鎖的資源奕污,面對已經(jīng)寫出去的 undo log 或者 redo log萎羔,參與者會一時陷入手足無措的狀態(tài),為了解決這個問題碳默,3PC 應運而生贾陷。
3階提交 Three Phase Commitment
3PC 在 commit 之前增加了 preCommit 的過程,使得在參與者在收不到確認時嘱根,依然可以從容 commit 或者 rollback髓废,避免資源鎖定太久導致浪費。但是 3PC 同樣存在著很多問題儿子。實現(xiàn)起來非常復雜瓦哎,因為很難通過多次詢問來解決系統(tǒng)間分歧問題,尤其是存在超時狀態(tài)互不信任的分布式網(wǎng)絡中,這也就是著名的拜占庭將軍問題蒋譬。
MySQL 分布式事務
XA 事務就是兩階段提交的一種實現(xiàn)方式割岛。
MySQL InnoDB 存儲引擎提供了對 XA 事務的支持,并通過 XA 事務來支持分布式事務的實現(xiàn)犯助。
XA 事務由如下組成:
- 一個或多個資源管理器:提供訪問事務資源的方法癣漆。通常一個數(shù)據(jù)庫就是一個資源管理器。 例如 MySQL 數(shù)據(jù)庫剂买。
- 一個事務管理器:協(xié)調(diào)參與全局事務中的各個事務惠爽。需要和參與全局事務的所有資源管理器進行通信。 例如連接 MySQL 服務端的客戶端瞬哼。
- 一個應用程序:定義事務的邊界婚肆,指定全局事務中的操作。