接之前一篇《Seata如何實現兩階段提交(2PC)分布式事務》,實際開發中seata基本不會用file存儲和管理服務節點信息,下面小編將結合nacos來整合seata,實現XA和AT模式的靈活轉換。
相關安裝包可以自行前往官網下載:
registry.conf:
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "nacos" nacos { application = "seata-tc-server" serverAddr = "127.0.0.1:8848" group = "DEFAULT_GROUP" namespace = "" cluster = "BJ" username = "nacos" password = "nacos" }}config { # file、nacos 、apollo、zk、consul、etcd3 type = "nacos" nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" dataId = "seataServer.properties" }}
seataServer.properties:
特別注意,為了讓TC服務的集群可以共享配置,同樣選擇nacos作為統一配置中心。
# 數據存儲方式,db代表數據庫store.mode=dbstore.db.datasource=druidstore.db.dbType=mysqlstore.db.driverClassName=com.mysql.cj.jdbc.Driverstore.db.url=jdbc:mysql://localhost:3306/seata?useUnicode=true&rewriteBatchedStatements=truestore.db.user=rootstore.db.password=rootstore.db.minConn=5store.db.maxConn=30store.db.globalTable=global_tablestore.db.branchTable=branch_tablestore.db.queryLimit=100store.db.lockTable=lock_tablestore.db.maxWait=5000# 事務、日志等配置server.recovery.committingRetryPeriod=1000server.recovery.asynCommittingRetryPeriod=1000server.recovery.rollbackingRetryPeriod=1000server.recovery.timeoutRetryPeriod=1000server.maxCommitRetryTimeout=-1server.maxRollbackRetryTimeout=-1server.rollbackRetryTimeoutUnlockEnable=falseserver.undo.logSaveDays=7server.undo.logDeletePeriod=86400000# 客戶端與服務端傳輸方式transport.serialization=seatatransport.compressor=none# 關閉metrics功能,提高性能metrics.enabled=falsemetrics.registryType=compactmetrics.exporterList=prometheusmetrics.exporterPrometheusPort=9898
sql腳本:
CREATE TABLE `branch_table` ( `branch_id` bigint(20) NOT NULL, `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `transaction_id` bigint(20) NULL DEFAULT NULL, `resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `status` tinyint(4) NULL DEFAULT NULL, `client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `gmt_create` datetime(6) NULL DEFAULT NULL, `gmt_modified` datetime(6) NULL DEFAULT NULL, PRIMARY KEY (`branch_id`) USING BTREE, INDEX `idx_xid`(`xid`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;CREATE TABLE `global_table` ( `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `transaction_id` bigint(20) NULL DEFAULT NULL, `status` tinyint(4) NOT NULL, `application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `timeout` int(11) NULL DEFAULT NULL, `begin_time` bigint(20) NULL DEFAULT NULL, `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `gmt_create` datetime NULL DEFAULT NULL, `gmt_modified` datetime NULL DEFAULT NULL, PRIMARY KEY (`xid`) USING BTREE, INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE, INDEX `idx_transaction_id`(`transaction_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
以上是XA模式所需腳本,AT模式追加以下腳本:
CREATE TABLE `lock_table` ( `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `transaction_id` bigint(20) NULL DEFAULT NULL, `branch_id` bigint(20) NOT NULL, `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `gmt_create` datetime NULL DEFAULT NULL, `gmt_modified` datetime NULL DEFAULT NULL, PRIMARY KEY (`row_key`) USING BTREE, INDEX `idx_branch_id`(`branch_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;CREATE TABLE `undo_log` ( `branch_id` bigint(20) NOT NULL COMMENT 'branch transaction id', `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'global transaction id', `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'undo_log context,such as serialization', `rollback_info` longblob NOT NULL COMMENT 'rollback info', `log_status` int(11) NOT NULL COMMENT '0:normal status,1:defense status', `log_created` datetime(6) NOT NULL COMMENT 'create datetime', `log_modified` datetime(6) NOT NULL COMMENT 'modify datetime', UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'AT transaction mode undo table' ROW_FORMAT = Compact;
其中lock_table導入到TC服務關聯的數據庫,undo_log表導入到微服務關聯的數據庫。
啟動seata:
圖片
XA 規范 是 X/Open 組織定義的分布式事務處理(DTP,Distributed Transaction Processing)標準,XA 規范描述了全局的TM與局部的RM之間的接口,幾乎所有主流的數據庫都對 XA 規范提供了支持。
XA是規范,目前主流數據庫都實現了這種規范,實現的原理都是基于兩階段提交。
圖片
圖片
一階段(準備階段):
事務協調者向所有參與此次分布式事務的本地事務參與者發出指令,要求它們開始執行本地事務操作。
二階段(提交/回滾階段):
接收到“全局提交”指令的參與者將在本地正式提交其事務,釋放之前持有的數據庫鎖,并確保事務操作永久記錄于數據庫。
圖片
在分布式事務處理中,RM和TC按照兩階段提交協議執行各自的工作:
RM在一階段的工作:
RM在數據庫或其他資源上執行與分支事務相關的SQL操作,但并不提交這些變更,而是保持數據鎖定狀態以防止數據不一致。
完成本地操作后,RM向TC報告其分支事務的執行狀態,包括成功或失敗的信息。
TC在二階段的工作:
若所有分支事務均執行成功,TC通知所有RM提交各自的事務。
若存在任何一個分支事務執行失敗,TC則指示所有RM回滾各自的事務,以保證分布式事務的一致性。
RM在二階段的工作:
如果是提交指令,則正式提交一階段執行的SQL操作,并釋放之前持有的鎖。
如果是回滾指令,則撤銷一階段未提交的SQL操作,恢復至事務開始前的數據狀態。
依賴引入:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.2.3.RELEASE</version> <exclusions> <!--版本較低,1.3.0,因此排除--> <exclusion> <artifactId>seata-spring-boot-starter</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency></dependencies>
配置引入:
server: port: 8011spring: application: name: bank-11 datasource: url: jdbc:mysql://localhost:3306/bank1?characterEncoding=utf8&useSSL=false driver-class-name: com.mysql.jdbc.Driver username: root password: root cloud: nacos: server-addr: 127.0.0.1:8848seata: registry: type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: "" group: DEFAULT_GROUP application: seata-tc-server # tc服務在nacos中的服務名稱 username: nacos password: nacos tx-service-group: order_tx_group #自定義事務組名稱需要與seata-server中的對應 data-source-proxy-mode: XA service: vgroup-mapping: order_tx_group: BJ # TC 集群(必須與seata-server保持一致)
bank22服務參考bank11配置即可,bank11調用bank22服務
@GlobalTransactional@Overridepublic void updateAccountBalance(String accountNo, Double amount) { log.info("******** Bank1 Service Begin ... xid: {}" , RootContext.getXID()); //張三扣減金額 baseMapper.updateAccountBalance(accountNo,amount); //向李四轉賬 String transfer = bank2Client.transfer(amount); if("fallback".equals(transfer)){ //調用李四微服務異常 throw new RuntimeException("調用李四微服務異常"); } //人為制造錯誤 if(amount > 100){ throw new RuntimeException("bank1 make exception amount > 100"); }}
XA模式的優點:
XA模式的缺點:
AT模式同樣是分階段提交的事務模型,不過卻彌補了XA模型中資源鎖定周期過長的缺陷。
階段一(準備階段)RM的工作:
當全局事務開始后,RM會為該事務涉及的本地事務創建并注冊一個分支事務,將其納入到全局事務的管理范圍。
在執行業務SQL之前,RM會對當前事務要修改的數據進行前鏡像的記錄,即生成undo-log。這樣在事務回滾時可以根據undo-log恢復到事務開始前的狀態。
RM按照業務需求執行相應的SQL操作,并在本地將事務置為“預提交”狀態,但不真正完成提交。
將分支事務的執行結果(成功或失敗)匯報給協調者,等待協調者的下一步指令。
階段二(提交階段/回滾階段)RM的工作:
如果協調者收到所有RM的反饋均為“準備成功”,則指示RM正式提交事務。此時,RM刪除對應的undo-log,因為事務已成功提交,不再需要回滾信息。
若協調者決定全局事務需要回滾,RM會根據先前記錄的undo-log恢復數據到事務開始前的狀態,撤銷在事務過程中對數據的所有更改,確保數據一致性。
修改配置:
seata: data-source-proxy-mode: AT # 默認就是AT
AT模式的優點:
- 一階段完成直接提交事務,釋放數據庫資源,性能比較好
- 利用全局鎖實現讀寫隔離
- 沒有代碼侵入,框架自動完成回滾和提交
AT模式的缺點:
- 兩階段之間屬于軟狀態,屬于最終一致
- 框架的快照功能會影響性能,但比XA模式要好很多
本文鏈接:http://www.www897cc.com/showinfo-26-70466-0.html利用Nacos實現Seata事務模式(XA與AT)的快速配置與靈活切換
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com