個(gè)人學(xué)習(xí)分布式事務(wù)的總結(jié)坟岔,引用了很多優(yōu)秀文章的闡述谒兄。如有版權(quán)問題,請(qǐng)告知社付。
事務(wù)的特點(diǎn)
事務(wù)擁有以下四個(gè)特性承疲,習(xí)慣上被稱為ACID特性。
- 原子性(Atomicity):事務(wù)作為一個(gè)整體被執(zhí)行鸥咖,包含在其中的對(duì)數(shù)據(jù)庫的操作要么全部被執(zhí)行燕鸽,要么都不執(zhí)行。
- 一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個(gè)一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致狀態(tài)啼辣。一致狀態(tài)是指數(shù)據(jù)庫中的數(shù)據(jù)應(yīng)滿足完整性約束啊研。除此之外,一致性還有另外一層語義鸥拧,就是事務(wù)的中間狀態(tài)不能被觀察到(這層語義也有說應(yīng)該屬于原子性)党远。
- 隔離性(Isolation):多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),一個(gè)事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行富弦,如同只有這一個(gè)操作在被數(shù)據(jù)庫所執(zhí)行一樣沟娱。
- 持久性(Durability):已被提交的事務(wù)對(duì)數(shù)據(jù)庫的修改應(yīng)該永久保存在數(shù)據(jù)庫中。在事務(wù)結(jié)束時(shí)腕柜,此操作將不可逆轉(zhuǎn)济似。
本地事務(wù)
本地事務(wù)一般指數(shù)據(jù)庫單庫事務(wù)柳爽。傳統(tǒng)關(guān)系數(shù)據(jù)庫對(duì)事務(wù)支持已經(jīng)非常完善。主流的開發(fā)框架碱屁,比如Spring,針對(duì)傳統(tǒng)數(shù)據(jù)庫的事務(wù)提供了便捷的支持蛾找,通過配置或者注解等方式來控制事務(wù)娩脾。
分布式事務(wù)
規(guī)模龐大的系統(tǒng),就要跟分布式事務(wù)打交道了打毛。主要的一些業(yè)務(wù)場(chǎng)景如下柿赊。
分庫分表
數(shù)據(jù)庫做水平切分時(shí),一個(gè)SQL操作會(huì)涉及多個(gè)數(shù)據(jù)庫幻枉,這些操作需要在一個(gè)事務(wù)中完成碰声。MyCat支持分布式事務(wù)。
微服務(wù)
業(yè)務(wù)拆分成眾多微服務(wù)之后熬甫,業(yè)務(wù)的調(diào)用鏈條變長(zhǎng)了胰挑,可能涉及眾多服務(wù)、數(shù)據(jù)庫椿肩、消息服務(wù)瞻颂,所有的資源操作需要在一個(gè)事務(wù)中完成。
兩階段提交
XA是一個(gè)分布式事務(wù)協(xié)議郑象。XA分為兩部分:事務(wù)管理器(Transaction Manager)和本地資源管理器(Resource Manager)贡这。其中本地資源管理器往往由數(shù)據(jù)庫實(shí)現(xiàn),比如Oracle厂榛、DB2這些商業(yè)數(shù)據(jù)庫都實(shí)現(xiàn)了XA接口盖矫,而事務(wù)管理器作為全局的調(diào)度者,負(fù)責(zé)各個(gè)本地資源的提交和回滾击奶。2PC和3PC提交都是基于XA協(xié)議實(shí)現(xiàn)的辈双。
兩階段提交的問題
同步阻塞問題。執(zhí)行過程中柜砾,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的辐马。當(dāng)參與者占有公共資源時(shí),其他第三方節(jié)點(diǎn)訪問公共資源不得不處于阻塞狀態(tài)局义。
單點(diǎn)故障喜爷。由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障萄唇。參與者會(huì)一直阻塞下去檩帐。尤其在第二階段,協(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)的問題)
數(shù)據(jù)不一致拔妥。在二階段提交的階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求之后达箍,發(fā)生了局部網(wǎng)絡(luò)異趁涣或者在發(fā)送commit請(qǐng)求過程中協(xié)調(diào)者發(fā)生了故障,這回導(dǎo)致只有一部分參與者接受到了commit請(qǐng)求缎玫。而在這部分參與者接到commit請(qǐng)求之后就會(huì)執(zhí)行commit操作硬纤。但是其他部分未接到commit請(qǐng)求的機(jī)器則無法執(zhí)行事務(wù)提交。于是整個(gè)分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象赃磨。
二階段無法解決的問題:協(xié)調(diào)者再發(fā)出commit消息之后宕機(jī)筝家,而唯一接收到這條消息的參與者同時(shí)也宕機(jī)了。那么即使協(xié)調(diào)者通過選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者邻辉,這條事務(wù)的狀態(tài)也是不確定的溪王,沒人知道事務(wù)是否被已經(jīng)提交。
TCC
補(bǔ)償性事務(wù)大致含義是值骇,"補(bǔ)償是一個(gè)獨(dú)立的支持ACID特性的本地事務(wù)在扰,用于在邏輯上取消服務(wù)提供者上一個(gè)ACID事務(wù)造成的影響,對(duì)于一個(gè)長(zhǎng)事務(wù)(long-running transaction)雷客,與其實(shí)現(xiàn)一個(gè)巨大的分布式ACID事務(wù)芒珠,不如使用基于補(bǔ)償性的方案,把每一次服務(wù)調(diào)用當(dāng)做一個(gè)較短的本地ACID事務(wù)來處理搅裙,執(zhí)行完就立即提交”皱卓。
confirm和cancel就是補(bǔ)償事務(wù),用于取消try階段本地事務(wù)造成的影響部逮。因?yàn)榈谝浑A段try只是預(yù)留資源娜汁,之后必須要明確的告訴服務(wù)提供者,這個(gè)資源你到底要不要兄朋,對(duì)應(yīng)第二階段的confirm/cancel掐禁。
可靠消息最終一致性
可靠消息最終一致性是指產(chǎn)生消息的業(yè)務(wù)動(dòng)作與消息發(fā)送的一致。也就是說颅和,如果業(yè)務(wù)操作成功傅事,那么由這個(gè)業(yè)務(wù)操作所產(chǎn)生的消息一定要成功投遞出去(一般是發(fā)送到kafka、rocketmq峡扩、rabbitmq等消息中間件中)蹭越,否則就丟消息。
阿里云提供的MQ和MNS兩種消息產(chǎn)品都支持事務(wù)型消息教届,將這個(gè)特性跟數(shù)據(jù)庫事務(wù)結(jié)合响鹃,可以實(shí)現(xiàn)基于可靠消息的最終一致性驾霜。
GTS
GTS是阿里云提供的全局事務(wù)服務(wù)。GTS 支持 DRDS买置、RDS粪糙、Oracle、MySQL忿项、PostgreSQL蓉冈、OceanBase 和 Petadata 等多種數(shù)據(jù)源,可以配合 EDAS倦卖、Dubbo 和 Spring Cloud 等微服務(wù)框架使用, 兼容 MQ 實(shí)現(xiàn)事務(wù)消息椿争。通過各種組合怕膛,可以輕松實(shí)現(xiàn)分布式數(shù)據(jù)庫事務(wù)、多庫事務(wù)秦踪、消息事務(wù)褐捻、服務(wù)鏈路級(jí)事務(wù)等多種業(yè)務(wù)需求。
針對(duì)不同的應(yīng)用場(chǎng)景椅邓,GTS 主要提供標(biāo)準(zhǔn)模式(AT)和自定義模式(MT)兩種事務(wù)模式柠逞。AT模式會(huì)依賴數(shù)據(jù)庫,用戶需要?jiǎng)?chuàng)建txc_undo_log
表景馁。MT模式更像TCC板壮,用戶需要自己實(shí)現(xiàn)兩階段提交的邏輯。
AT 模式
AT 模式是 GTS 最主要的事務(wù)模式合住,通過 GTS 基于 DRDS/RDS 的數(shù)據(jù)源绰精,對(duì) SQL 語句提供分布式事務(wù)支持。它幫助應(yīng)用方以最小的改造代價(jià)來實(shí)現(xiàn)數(shù)據(jù)庫的事務(wù)功能透葛。
AT 模式適合于 DRDS 分庫分表笨使、多數(shù)據(jù)庫數(shù)據(jù)源、跨進(jìn)程的多數(shù)據(jù)庫數(shù)據(jù)源等幾乎任何 DRDS 應(yīng)用場(chǎng)景下的分布式事務(wù)僚害。
MT 模式
MT模式提供用戶可以介入兩階段提交過程的一種模式硫椰。在這種模式下,用戶可以根據(jù)自身業(yè)務(wù)需求自定義在 GTS 的兩階段中每個(gè)階段的具體行為萨蚕。MT 模式提供了更多的靈活性靶草,可能性,以達(dá)到特殊場(chǎng)景下的自定義優(yōu)化岳遥,及特殊功能的實(shí)現(xiàn)爱致。
MT 模式不依賴于數(shù)據(jù)庫,這是它相對(duì)于 AT 模式的一個(gè)最大的優(yōu)勢(shì)寒随。MT 模式幾乎滿足任何事務(wù)場(chǎng)景糠悯。
樣例
GTS提供了豐富的樣例幫助大家理解產(chǎn)品的原理和使用帮坚。
基于消息的最終一致性
sample-txc-mq
這個(gè)例子使用MQ實(shí)現(xiàn)的最終一致性。循環(huán)轉(zhuǎn)賬十次互艾,前五次會(huì)成功试和,后五次會(huì)因?yàn)橛囝~不足而失敗。
[root@izuf60wa1jflm222pngldrz bin]# ./run.sh
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
JM.Log:INFO Init JM logger with Slf4jLoggerFactory success, sun.misc.Launcher$AppClassLoader@4617c264
JM.Log:INFO Log root path: /root/logs/
JM.Log:INFO Set txc log path: /root/logs/txc
JM.Log:INFO Set diamond-client log path: /root/logs/diamond-client
client mode:3 [0:None (only be client) 1:Default Mode 2:Manual Mode 3:Default Mode & Manual Mode 5:Default Mode & Service Mode 6:Manual Mode & Service Mode 7:Default Mode & Manual Mode &Service Mode]
txcAppName:gts_henshao_test.1162142976628250.SH
txcServerGroup:gts_henshao_test.1162142976628250.SH
Sat Dec 15 15:56:46 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Sat Dec 15 15:56:46 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Producer started!
Sat Dec 15 15:56:46 CST 2018
send msgId:AC139F2C46554617C26448F1D3960000 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:80元
本次轉(zhuǎn)賬結(jié)束纫普,A和B的余額為:
A賬戶現(xiàn)在余額為80元
B賬戶現(xiàn)在余額為120元
A和B的金額總和為200元
Sat Dec 15 15:56:47 CST 2018
Sat Dec 15 15:56:48 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Sat Dec 15 15:56:48 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
send msgId:AC139F2C46554617C26448F1D6BC0003 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:60元
本次轉(zhuǎn)賬結(jié)束阅悍,A和B的余額為:
A賬戶現(xiàn)在余額為60元
B賬戶現(xiàn)在余額為140元
A和B的金額總和為200元
Sat Dec 15 15:56:48 CST 2018
send msgId:AC139F2C46554617C26448F1D9D10006 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:40元
本次轉(zhuǎn)賬結(jié)束,A和B的余額為:
A賬戶現(xiàn)在余額為40元
B賬戶現(xiàn)在余額為160元
A和B的金額總和為200元
Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DA7E0009 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:20元
本次轉(zhuǎn)賬結(jié)束昨稼,A和B的余額為:
A賬戶現(xiàn)在余額為20元
B賬戶現(xiàn)在余額為180元
A和B的金額總和為200元
Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DAFE000C status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:0元
本次轉(zhuǎn)賬結(jié)束节视,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DB80000F status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:-20元
not enough money. 回滾到事務(wù)前狀態(tài)
本次轉(zhuǎn)賬結(jié)束,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DCF60012 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:-20元
not enough money. 回滾到事務(wù)前狀態(tài)
本次轉(zhuǎn)賬結(jié)束假栓,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DDC20015 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:-20元
not enough money. 回滾到事務(wù)前狀態(tài)
本次轉(zhuǎn)賬結(jié)束寻行,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DE870018 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:-20元
not enough money. 回滾到事務(wù)前狀態(tài)
本次轉(zhuǎn)賬結(jié)束,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DF75001B status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中間狀態(tài)為:-20元
not enough money. 回滾到事務(wù)前狀態(tài)
本次轉(zhuǎn)賬結(jié)束匾荆,A和B的余額為:
A賬戶現(xiàn)在余額為0元
B賬戶現(xiàn)在余額為200元
A和B的金額總和為200元
wait for several seconds ------------------
checking result --------------------
A原來來有100元拌蜘,現(xiàn)在為0元
B原來來有100元,現(xiàn)在為200元
A和B的金額總和為200元
三個(gè)分支事務(wù)分別是兩個(gè)數(shù)據(jù)庫牙丽,一個(gè)MQ消息简卧。
去MQ里面可以看到一共發(fā)送了五條消息,失敗的五條是看不到的烤芦。
預(yù)留和補(bǔ)償事務(wù)
MT模式的兩個(gè)例子举娩,預(yù)留事務(wù)是在rollin的時(shí)候預(yù)留資源,commitRollin的時(shí)候操作資源及刪除分支事務(wù)的數(shù)據(jù)构罗。補(bǔ)償事務(wù)則是在rollin的時(shí)候就操作資源晓铆,commitRollin的時(shí)候只刪除分支事務(wù)的數(shù)據(jù)。