事務失敗返回 分庫分表下事務問題的一些解決思路

2021-10-14 18:21:22 字數 4346 閱讀 7166

本次在做分庫分表時,遇到了跨庫事務的問題。通過在網上搜尋了許多資料後找了一些解決該問題的方法與思路。本文將分為兩部分分別介紹常用的分布式事務解決方案以及本次分庫分表中如何去解決跨庫事務的實踐。

2pc即為兩階段提交,是一種在多節點間實現事務原子提交的演算法,用來確保所有節點要麼全部提交,要麼全部中止。我們可以有多種方案來實現該演算法,如基於xa協議的實現,阿里也提供了seata中介軟體支援2pc演算法。

根據圖示可以發現我們引入了乙個新元件叫做「協調者」(也稱事務管理者),他的作用是協調所有參與者的提交與回滾操作。

2pc既然叫做兩階段提交,那必然是分成了兩個階段。

準備階段:協調者會在準備階段給所有參與者都傳送準備命令。如果參與者發現準備命令無法執行或者執行失敗時,可以返回失敗,如果執行完成則儲存事務日誌並返回成功。針對於資料庫的操作,準備階段會記錄redolog以及undolog為後續的提交做準備。需要注意的是在準備階段時,資料實際是沒有被真正儲存的

提交階段:協調者在提交階段會根據準備階段各個參與者的返回結果,判斷是執行事務還是回滾事務並向所有參與者發起提交命令。其中只有當準備階段的所有節點都返回成功,協調者才會傳送執行事務的命令。如果有乙個參與者返回失敗,那麼協調者就會向所有參與者傳送回滾事務的請求,即分布式事務執行失敗。

優點:- a. 保證了事務是強一致性的 - b. 實現相對簡單

缺陷:- a. 同步阻塞問題,如果其中乙個參與者響應超時,其他所有參與者都需要等待。 - b. 增加死鎖風險,由於每個參與者都可能長時間鎖定資源,因此死鎖的風險大大加大了 - c. 單點故障問題,如果協調者出現問題。其他所有參與者將無法判斷應該提交事務或回滾

以下為2pc的一種簡單實現方法的偽**。

@target(elementtype.method)

@retention(retentionpolicy.runtime)

@documented

public @inte***ce multitransactional ;

}public class twopctransactionaspect

private callable _starttransaction(callable callable, string dsname) catch (throwable e) };}

}

tcc分別指的是三個步驟,try - confirm - cancel。與2pc類似,它在邏輯也會分成準備和提交兩個階段。但是最大的不同在於tcc需要業務服務自己去實現準備、執行、回滾的**,因此可以做到非常靈活。

try:對資源的預留和鎖定confirm:確認操作,是對事務的真正執行。cancel撤銷操作,把預留階段的資源撤銷。

從圖中其實我們能發現tcc與2pc的操作基本是一致的。只是2pc針對於資料庫操作,tcc可以讓服務方自己去實現相應操作。

優點:- a. 實現很靈活,幾乎可以滿足任何分布式事務的場景

缺點:- a. 與業務**耦合度高,開發複雜度大大提公升 - b. confirm,cancel操作需要考慮冪等性 - c. 其實實現思想還是依據2pc,因此包含了2pc所有缺點

tcc的內部實現還是比較複雜的,因此可以引入一些專門的tcc框架,如bytetcc,himly等。

此處的實現僅僅是基於tcc思想的一種偽**簡單實現:

public class tccservice  catch (exception e) 

}}public class servicea implements tccsampleinte***ce

@override

public void doconfirm()

@override

public void docancel()

}public class serviceb implements tccsampleinte***ce

@override

public void doconfirm()

@override

public void docancel()

}

最大努力通知顧名思義就是盡可能的保證事務的最終一致性,是一種柔性事務的思想。他有許多種實現方式,本文只講解其中一種:本地訊息表 本地訊息表其實就是使用了一張額外的表儲存了操作的日誌。

根據上圖,本地訊息表的實現方式會在第乙個操作完成之後記錄事務日誌。需要注意的是記錄事務日誌與第乙個操作請求是在乙個事務中的,這樣保證了日誌記錄在操作成功後一定會記下。後續的操作如果更新成功了,則更新日誌記錄表為成功,如果失敗了則更新日誌表為失敗。後台會有定時任務定期去掃瞄事務日誌表,對失敗的操作進行回放,以此來保證事務的最終一致性。

優點:

缺點:

分布式事務解決方式

適用場景

2pc資料庫層面的分布式事務場景

tcc跨不同業務系統的分布式事務場景

最大努力通知

對事務一致性要求不高的場景

本次分庫分表時針對於訊息服務做的,接下來將以訊息服務中最經典的乙個操作,「傳送訊息」場景進行舉例。

傳送訊息的流程主要分為四步: 1. 發起傳送訊息的請求 2. 儲存訊息至訊息表(訊息表在db1的資料庫) 3. 會話表中該會話訊息數量+1(會話表在db2的資料庫) 4. 會話傳送成功

傳送訊息這個場景的特點在於:

因此採用了本地訊息表來實現事務的最終一致性

具體實現流程圖如下:

為方便理解,**有所修改。

@target(elementtype.method)

@retention(retentionpolicy.runtime)

@documented

public @inte***ce transactionlog

@aspect

@component

@suppresswarnings()

@slf4j

public class transactionlogaspect

});}

private void proceed(proceedingjoinpoint pjp, imessagetransactionlogrepository logrepo, long logid) catch (throwable e) catch (exception ex) }}

}

/**

* 傳送訊息

**/

@transcational("db1") //使用db1的事務

@override

public void sendmessages(session session)

/** * 更新會話的訊息數量

**/

@transactionlog(parametertypes = , generictypes = )

public void updatemessagecountwithtransactionlog(long sessionid, integer count)

2pc是強一致性的事務,適合用在資料庫層面。

tcc也是強一致性的事務,適合大部分場景,但是對業務**有侵入,開發量也很大。

最大努力通知是一種柔性事務,用各種方式去維持事務的最終一致性。

本文介紹的分庫分表事務一致性實現,使用的就是最大努力通知的本地訊息表實現。

分布式事務是分布式系統中非常頭疼的乙個環節,我們需要在不同的場景使用不同的解決方案。

但是也不難發現,無論哪一種方式都有自己的利弊,實現都較為複雜,因此我的建議是:能避免使用分布式事務,就避免

分庫分表下事務問題的一些解決思路​zhuanlan.zhihu.com

《資料密集型應用系統設計》

事務失敗返回 分布式事務方案 TCC

tcc是支付寶提出的分布式事務解決方案,是 try confirm cancel 的縮寫。與2pc二階段提交機制類似,區別在於層面不同,2pc是在資料庫層面解決資料庫之間的分布式事務,tcc是在應用層面解決分布式系統中的分布式事務。每個分布式事務的參與者都需要實現3個介面 try confirm c...

資料庫分庫分表事務解決方案

隨著時間和業務的發展,資料庫中表的資料量會越來越大,相應地,資料操作,增刪改查的開銷也會越來越大。因此,把其中一些大表進行拆分到多個資料庫中的多張表中。另一方面,在分庫分表以後還需要保證分庫分表的和主庫的事務一致性。這片文章介紹一下 本篇文章是基於非事務訊息的非同步確保的方式來完成分庫分表中的事務問...

分庫分表實戰問題

1.分庫分表中水平拆分和垂直拆分的區別?水平拆分 將表資料拆分到不同的資料資料庫中。垂直拆分 把乙個大表拆成多個小表。字段進行拆分。分表 是指的是把表資料拆分到多張表裡面。range分發 每個月生成乙個新錶。如果訪問新的資料還好,但是訪問舊的資料就麻煩一些。hash分發 平均分配,但是擴容的話會比較...