EasyTransaction一站式解決分布式 SOA 事務(wù)問題
一、由來
這個框架是結(jié)合齊牛金融公司之前遇到的分布式事務(wù)場景以及 支付寶程立分享的一個PPT<大規(guī)模SOA系統(tǒng)的分布式事務(wù)處理>而設(shè)計實現(xiàn),意在解決之前公司對于每個分布式事務(wù)場景中都自行重復(fù)設(shè)計中間狀態(tài)、冪等實現(xiàn)及重試邏輯的狀況。采納本框架后能解決現(xiàn)有已發(fā)現(xiàn)的所有分布式事務(wù)場景,減少設(shè)計開發(fā)設(shè)計工作量,提高開發(fā)效率,并統(tǒng)一保證事務(wù)實現(xiàn)的可靠性。
二、分布式事務(wù)場景及框架對應(yīng)實現(xiàn)
分布式事務(wù)場景
無需分布式事務(wù)
最常用
最優(yōu)先使用
使用消息隊列完成的最終一致性事務(wù)
適用于業(yè)務(wù)主邏輯無需外部數(shù)據(jù)變更協(xié)助來完成的最終一致性事務(wù)
常見
若一定要與其他服務(wù)寫接口發(fā)生交互,則優(yōu)先使用
依據(jù)是否保證投遞到訂閱者,分為可靠消息及最大努力交付消息
有時業(yè)務(wù)需求一些本質(zhì)是異步操作,但是盡可能同步返回結(jié)果,這本質(zhì)也歸屬于這一類,但介于其有返回值,同步時可返回結(jié)果,其有區(qū)別于可靠消息。
使用傳統(tǒng)補(bǔ)償完成的最終一致性事務(wù)
適用于需要獲知遠(yuǎn)程執(zhí)行結(jié)果來決定邏輯事務(wù)走向 且 可以進(jìn)行補(bǔ)償?shù)臉I(yè)務(wù)
次常見
若使用消息隊列不能解決的事務(wù)問題優(yōu)先考慮使用基于補(bǔ)償?shù)淖罱K一致性事務(wù)
使用TCC完成最終一致性事務(wù)
適用于需要獲知遠(yuǎn)程執(zhí)行結(jié)果來決定邏輯事務(wù)走向 且 不可以進(jìn)行補(bǔ)償?shù)臉I(yè)務(wù)
最不常見
最終解決辦法,囊括所有必須使用2PC實現(xiàn)的場景。編碼量最大,性能消耗最大,應(yīng)盡量避免使用本類型的事務(wù)
框架對應(yīng)實現(xiàn)及基本原理
框架實現(xiàn)了上述所有事物場景的解決方案,并提供了統(tǒng)一易用的接口。以下介紹基本實現(xiàn)原理
無需分布式事務(wù)
對于此類事務(wù),框架完全不介入,不執(zhí)行一行額外代碼
其他事務(wù)場景
框架的核心依賴是Spring的TransactionSynchronization,只要使用的事務(wù)管理器繼承自AbstractPlatformTransactionManager都能使用本框架(基本上都集成自本實現(xiàn))。
對于分布式事務(wù),框架會在調(diào)用遠(yuǎn)程事務(wù)方法后,將對應(yīng)的框架操作掛載到TransactionSynchronization中,如:
使用消息隊列完成的最終一致性事務(wù),框架將會在事務(wù)COMMIT后發(fā)發(fā)送消息,保證只有COMMIT后事務(wù)才能被外部看見,這里也省去業(yè)務(wù)開發(fā)者對于 發(fā)送-確認(rèn)-檢測 類型 隊列實現(xiàn)的代碼量
使用TCC完成最終一致性事務(wù),框架將會根據(jù)事務(wù)的實際完成情況調(diào)用Confirm或者Cancel,用傳統(tǒng)補(bǔ)償完成的最終一致性事務(wù)也類似
框架有后臺線程負(fù)責(zé)CRASH恢復(fù),其根據(jù)“在執(zhí)行分布式服務(wù)調(diào)用前寫入的WriteAheadLog獲得可能已經(jīng)調(diào)用的業(yè)務(wù)”以及“跟隨業(yè)務(wù)一起提交的一條框架記錄以確認(rèn)的業(yè)務(wù)最終提交狀態(tài)”來進(jìn)行最終的CRASH具體操作(如TCC的Confirm或者Rollback)
框架對于冪等也有完整的實現(xiàn)(可選),框架能保證業(yè)務(wù)方法邏輯上只執(zhí)行一遍(有可能執(zhí)行多遍,但多次執(zhí)行的方法會被回滾掉,因此,涉及不可回滾的外部資源時,業(yè)務(wù)程序需自行把控其冪等性)
框架對于方法間有調(diào)用關(guān)系依賴的也進(jìn)行妥善的處理,例如基于傳統(tǒng)補(bǔ)償完成的最終一致性事務(wù)中
業(yè)務(wù)方法沒有被調(diào)用,那么補(bǔ)償方法對應(yīng)的業(yè)務(wù)實現(xiàn)也不會被調(diào)用(但框架仍會記錄下補(bǔ)償方法已經(jīng)被調(diào)用過)
補(bǔ)償方法已經(jīng)被掉用過了,那么業(yè)務(wù)方法無論曾經(jīng)有沒有被執(zhí)行過,都不會被調(diào)用
所有遠(yuǎn)程調(diào)用的結(jié)果都是以Future形式返回,這給框架的性能優(yōu)化提供了空間,在第一次獲取結(jié)果前,所有的日志都不會被寫入所有遠(yuǎn)程方法都不會被調(diào)用。一旦業(yè)務(wù)程序嘗試獲取執(zhí)行結(jié)果時,才會批量寫入日志及后續(xù)并發(fā)調(diào)用遠(yuǎn)程方法。
如果業(yè)務(wù)程序沒有嘗試獲取執(zhí)行結(jié)果,框架COMMIT前會統(tǒng)一嘗試GET一遍,對于所有遠(yuǎn)程方法一旦拋出了Exception,框架都會在最后commit前將業(yè)務(wù)回滾,而無論之前是否catch住了,這樣能保證編程模型的簡潔,方便寫出正確易理解的代碼。
