做旅游網(wǎng)站的寫手關(guān)鍵詞排名優(yōu)化江蘇的團(tuán)隊(duì)
目錄
前言
1.sharding的分布式事務(wù)
2.分布式事務(wù)的產(chǎn)生原因
3.分布式事務(wù)的解決方案
3.1.DTP模型
3.2.分階段提交
3.3.TCC模式
3.4.可靠消息服務(wù)
3.5.AT模式
3.6.Seata
前言
本文是前面一篇文章聊了基于sharding的分庫分表后拓展出來的關(guān)于分布式事務(wù)的討論,本文中將詳細(xì)講一下sharding中的分布式事務(wù)以及市面上常見的分布式事務(wù)解決方案。
1.sharding的分布式事務(wù)
-
Sharding JDBC: Sharding JDBC 提供了對分布式事務(wù)的支持。它通過兩階段提交(2PC)協(xié)議來實(shí)現(xiàn)跨多個(gè)數(shù)據(jù)源的分布式事務(wù)。Sharding JDBC 會將事務(wù)中的操作發(fā)送到各個(gè)數(shù)據(jù)源執(zhí)行,并在提交階段協(xié)調(diào)所有數(shù)據(jù)源的提交操作,以保證事務(wù)的一致性。
-
Sharding Proxy: Sharding Proxy 本身并不直接支持分布式事務(wù)。它主要是一個(gè)中間件,負(fù)責(zé)路由和轉(zhuǎn)發(fā)客戶端的 SQL 請求到后端的多個(gè)數(shù)據(jù)源。在 Sharding Proxy 中,跨多個(gè)數(shù)據(jù)源的事務(wù)操作會被拆分成多個(gè)獨(dú)立的本地事務(wù),每個(gè)數(shù)據(jù)源獨(dú)立處理。這就意味著在 Sharding Proxy 中,跨多個(gè)數(shù)據(jù)源的事務(wù)并不會保證全局的一致性,需要應(yīng)用程序自行處理分布式事務(wù)的邏輯。
sharing jdbc后在spring boot中如何使用分布式事務(wù),代碼示例:
@Service public class MyService { ?@Autowiredprivate JdbcTemplate jdbcTemplate; ?@Transactionalpublic void performDistributedTransaction() {// 在事務(wù)范圍內(nèi)執(zhí)行數(shù)據(jù)庫操作jdbcTemplate.update("INSERT INTO table1 (column1) VALUES (?)", "value1");jdbcTemplate.update("INSERT INTO table2 (column1) VALUES (?)", "value2");// 手動拋出異常,模擬事務(wù)中的異常情況throw new RuntimeException("Simulated exception");} }
是的你沒看錯(cuò),不用任何額外的配置,就是用spring的事務(wù)即可。因?yàn)閟harding jdbc作為一個(gè)分庫分表的技術(shù)棧,天生就有分布式事務(wù)問題,所以其默認(rèn)就是開啟分布式事務(wù)的,它的事務(wù)都是兩階段提交的。
說到分布式事務(wù),我們來回顧一下之前聊過的分布式事務(wù)的內(nèi)容。
2.分布式事務(wù)的產(chǎn)生原因
分布式事務(wù)是指在在分布式架構(gòu)下一個(gè)事務(wù)中的不同子操作是在不同機(jī)器上執(zhí)行的,子操作之間狀態(tài)無法相互感知,其中有子操作出錯(cuò)后其他機(jī)器上的子操作無法正確回滾。
分布式事務(wù)產(chǎn)生的根本原因:各個(gè)服務(wù)之間無感知
舉一個(gè)例子:
一個(gè)下單事務(wù),包含創(chuàng)建訂單,庫存服務(wù),需要順序調(diào)用訂單服務(wù)、庫存服務(wù)。如果庫存服務(wù)掛掉后,訂單服務(wù)也是無法回滾的,因?yàn)橛唵畏?wù)感知不到庫存服務(wù)是否成功,即無法感知到庫存服務(wù)的狀態(tài)。
3.分布式事務(wù)的解決方案
3.1.DTP模型
1994年,X/Open組織(即現(xiàn)在的Open Group)定義了分布式事務(wù)處理的DTP模型,該模型包括幾個(gè)角色:
- 應(yīng)用程序(AP),服務(wù)
- 事務(wù)管理器(TM),全局事務(wù)管理者
- 資源管理器(RM),一般是數(shù)據(jù)庫
- 通信資源管理器(CRM),TM和RM之間的通信中間件
DTP模型中,一個(gè)分布式事務(wù)(全局事務(wù))可以被拆分成多個(gè)本地事務(wù),運(yùn)行在不同的AP和和RM上。每個(gè)本地事務(wù)的ACID由自身保證,全局事務(wù)必須保證每個(gè)本地事務(wù)必須同時(shí)成功,若有一個(gè)失敗其他事務(wù)必須回滾。由于本地事務(wù)之間相互是無法感知狀態(tài)的,因此要通過CRM來通知各個(gè)本地事務(wù),同步事務(wù)執(zhí)行的狀態(tài)。
由于各個(gè)本地事務(wù)之間需要通信,通信就需要標(biāo)準(zhǔn),因此配套提出了XA通信標(biāo)準(zhǔn)。XA規(guī)定了DTP中CRM和TM之間的通信的接口規(guī)范,定義了用于通知事務(wù)開始、提交、終止、回滾等接口,各個(gè)數(shù)據(jù)庫廠商之間必須實(shí)現(xiàn)該接口。
3.2.分階段提交
分階段提交,也叫兩階段提交(two-phase commit)。DTP模型落地實(shí)現(xiàn)的一種思想。
兩階段提交中,將事務(wù)分成兩個(gè)階段來執(zhí)行:
- 階段一,準(zhǔn)備階段,各個(gè)本地事務(wù)執(zhí)行自己事務(wù)內(nèi)的邏輯,完成提交前的準(zhǔn)備工作。
- 階段二,執(zhí)行階段,各個(gè)事務(wù)根據(jù)上一階段的執(zhí)行結(jié)果,進(jìn)行提交或者回滾。
兩階段提交中有兩個(gè)角色,協(xié)調(diào)者(coordinator)、參與者(voter)。
正常情況:
異常情況:
準(zhǔn)備階段協(xié)調(diào)者會詢問每個(gè)參與者是否可以執(zhí)行事務(wù),每個(gè)事務(wù)參與者執(zhí)行事務(wù)寫入redo、undo日志,然后反饋事務(wù)的執(zhí)行結(jié)果,只要有一個(gè)參與者返回的是disagree則說明失敗,協(xié)調(diào)者會像各個(gè)參與者發(fā)出abort指令,各個(gè)事務(wù)收到指令后各自回滾事務(wù)。
兩階段提交的優(yōu)點(diǎn):
- 方案成熟,很穩(wěn)
- 能保證強(qiáng)一致性
兩階段提交的缺點(diǎn):
- 單點(diǎn)故障,當(dāng)協(xié)調(diào)者掛了之后后續(xù)的步驟就沒辦法進(jìn)行了,被鎖住的數(shù)據(jù)沒辦法解鎖,會造成阻塞。
- 數(shù)據(jù)鎖定,分階段提交由于過程被拆成兩段,會造成本地事務(wù)的執(zhí)行過程變長,數(shù)據(jù)會長時(shí)間處于鎖定狀態(tài)。
3.3.TCC模式
TCC模式是專門用來解決分階段提交的缺陷的,減少數(shù)據(jù)鎖定,避免阻塞問題。
TCC相當(dāng)于是強(qiáng)化了兩階段提交,在分階段提交中埋入了以下幾個(gè)點(diǎn)位:
- try,資源的檢測和預(yù)留。
- confirm,執(zhí)行的業(yè)務(wù)操作提交,要求try成功的話confrim一定要能成功。
- cancel,預(yù)留資源釋放
經(jīng)過TCC的強(qiáng)化埋點(diǎn)后兩階段提交變成了:
- 準(zhǔn)備階段。try,資源預(yù)留,通知每個(gè)參與者去try一下數(shù)據(jù)資源,判斷一下數(shù)據(jù)資源是否足以支撐之后的事務(wù)運(yùn)行。每個(gè)參與者均try成功再執(zhí)行下一步,否則直接cancel。
- 執(zhí)行階段,confrim,讓協(xié)調(diào)者通知各個(gè)參與者執(zhí)行并提交事務(wù)(因?yàn)橘Y源已經(jīng)準(zhǔn)備好了,執(zhí)行和提交可以一氣呵成),各個(gè)參與者confrim成功則成功,但凡有一個(gè)失敗則通知協(xié)調(diào)者組織全局回滾、釋放資源、退出。
TCC的優(yōu)點(diǎn):
TCC其實(shí)每個(gè)階段都是單獨(dú)的事務(wù),try其實(shí)是個(gè)事務(wù)只是去摸一下看下階段要的數(shù)據(jù)資源是否能用,confrim則是原來的包含業(yè)務(wù)邏輯的事務(wù)。這樣的話就避免了兩階段提交中agree過程中對于數(shù)據(jù)的鎖定,盡量避免了影響其他事務(wù)的執(zhí)行。
TCC的缺點(diǎn):
- 編碼成本,存在代碼侵入需要開發(fā)人員手動編寫TCC三步,開發(fā)的成本會比較高。
- 弱一致性,TCC保證的是最終一致性,因?yàn)閱蝹€(gè)本地事務(wù)的執(zhí)行和提交都包含在confirm一個(gè)步驟中,如果出現(xiàn)問題回滾前其實(shí)是沒有保證一致性的,在這中間有其他讀操作進(jìn)來是能讀到已經(jīng)變動的數(shù)據(jù)的。
3.4.可靠消息服務(wù)
可靠消息服務(wù)起源自eBay,是將各個(gè)服務(wù)的本地事務(wù)串成一個(gè)鏈,依托MQ來保障分布式事務(wù),比如服務(wù)A執(zhí)行完服務(wù)后向MQ中存放自己執(zhí)行成功的信息,MQ再向服務(wù)B推送消息叫它執(zhí)行本地事務(wù),服務(wù)B執(zhí)行完本地事務(wù)后又告訴MQ,MQ繼續(xù)向后續(xù)要執(zhí)行本地事務(wù)的服務(wù)推送消息。
缺點(diǎn):
由于是MQ主動向后續(xù)服務(wù)推送消息,后續(xù)服務(wù)要是失敗了,前置服務(wù)感知不到,前置服務(wù)無法進(jìn)行感知回滾。。所以可靠消息服務(wù)適用的場景有限。
3.5.AT模式
AT模式是Alibaba的seata組件開源出來的一種分布式事務(wù)解決方案,是對TCC的一種優(yōu)化,解決了TCC模式中的的代碼侵入、編碼復(fù)雜等問題。
AT模式中,用戶只需關(guān)注自己的業(yè)務(wù)SQL,seata框架會自動生成書屋的二階段提交和回滾操作。
AT模式整個(gè)流程和TCC大致相同,不同點(diǎn)是在于AT模式將執(zhí)行放在了一階段:
- 一階段(開發(fā)者實(shí)現(xiàn)),正常編寫業(yè)務(wù)邏輯,然后執(zhí)行SQL,執(zhí)行本地事務(wù),并返回執(zhí)行結(jié)果。
- 二階段(框架托管),根據(jù)一階段的結(jié)果判斷二階段的做法,提交或者回滾。
?AT模式的底層原理:
在階段一的時(shí)候攔截下所有SQL,框架會去解析這條SQL然后去數(shù)據(jù)庫中查詢出要操作的數(shù)據(jù),存一份鏡像叫before image,接下來執(zhí)行SQL,執(zhí)行完SQL后再查詢一次,存一份叫after image。
到了階段二的時(shí)候,比對before鏡像和after鏡像從而判斷操作是否成功,如果一階段的所有本地事務(wù)操作都是成功的,就會清空before鏡像和after鏡像,如果有一個(gè)是失敗的各個(gè)本地事務(wù)就會根據(jù)屬于自己的before鏡像進(jìn)行回滾。
after鏡像是為了在回滾的時(shí)候進(jìn)行比對,要是回滾時(shí)發(fā)現(xiàn)數(shù)據(jù)庫中此時(shí)的數(shù)據(jù)和after鏡像中記錄的數(shù)據(jù)不相同,則說明數(shù)據(jù)又被動過了,產(chǎn)生了臟數(shù)據(jù),此時(shí)就需要人工介入了。由于行鎖的存在,產(chǎn)生臟數(shù)據(jù)的概率很低很低,after鏡像只是留了一手。
AT模式中的角色:
AT模式中一共有三個(gè)角色
- TC,服務(wù)協(xié)調(diào)者,是一個(gè)單獨(dú)的服務(wù)。
- TM,通信中間件。
- RM,資源管理器,管理分支的事務(wù)處理,與TC進(jìn)行通信注冊分支事務(wù)和報(bào)告事務(wù)狀態(tài),驅(qū)動分支事務(wù)提交或者回滾。
TM、RM和服務(wù)是耦合在一起的,但是不侵入代碼,以jar包的方式體現(xiàn)。
3.6.Seata
Seata是目前為止常用、流行切穩(wěn)定的分布式事務(wù)解決方案,其在使用上對代碼沒有侵入,直接是基于配置的,使用方法見官方手冊即可。在遇到分布式事務(wù)場景時(shí),可以優(yōu)先考慮使用seata來解決。