TX-LCN 分布式事務框架


第十章 TX-LCN 分布式事務框架
(Spring Cloud 高級)
一、 什么是分布式事務
分布式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位
於不同的分布式系統的不同節點之上。
舉個栗子:
電商系統中的訂單系統與庫存系統

 

 

圖中包含了庫存和訂單兩個獨立的微服務,每個微服務維護了自己的數據庫。在交易系
統的業務邏輯中,一個商品在下單之前需要先調用庫存服務,進行扣除庫存,再調用訂單服
務,創建訂單記錄。
 

 

 

正常情況下,兩個數據庫各自更新成功,兩邊數據維持着一致性。
如果在非正常情況下,有可能庫存的扣減完成了,隨后的訂單記錄卻因為某些原因插入
失敗。或者是訂單創建成功了,但是庫存扣除商品的數據量失敗了,這個時候,兩邊數據就
失去了應有的一致性。 

 

 

這時候就需要保證事務的一致性了,單數據源的用單機事務來保證。多數據源就需要依
賴分布式事務來處理。
 

二、 XA 的兩階段提交方案

 

1 什么是 XA 協議

 
XA 協議由 Oracle Tuxedo 首先提出的,並交給 X/Open 組織,作為資源管理器(數據庫)
與事務管理器的接口標准。目前,Oracle、Informix、DB2 和 Sybase 等各大數據庫廠家都提
供對 XA 的支持。XA 協議采用兩階段提交方式來管理分布式事務。XA 接口提供資源管理
器與事務管理器之間進行通信的標准接口。
XA 就是 X/Open DTP 定義的交易中間件與數據庫之間的接口規范(即接口函數),交
易中間件用它來通知數據庫事務的開始、結束以及提交、回滾等。XA 接口函數由數據庫廠
商提供。
X/Open 組織(即現在的 Open Group)定義了分布式事務處理模型。X/Open DTP 模型
(1994)包括應用程序(AP)、事務管理器(TM)、資源管理器(RM)、通信資源管理
器(CRM)四部分。一般,常見的事務管理器(TM)是交易中間件,常見的資源管理器(RM)
是數據庫,常見的通信資源管理器(CRM)是消息中間件。
 

2 XA 協議的一階段提交 

 

 

如果在程序中開啟了事務,那么在應用程序發出提交/回滾請求后,數據庫執行操作,
而后將成功/失敗返回給應用程序,程序繼續執行。
一階段提交協議相對簡單。優點也很直觀,它不用再與其他的對象交互,節省了判斷
步驟和時間,所以在性能上是在階段提交協議中最好的。但缺點也很明顯:數據庫確認執行
事務的時間較長,出問題的可能性就隨之增大。如果有多個數據源,一階段提交協議無法協
調他們之間的關系。
 
 

3 XA 協議的二階段提交

 
在一階段協議的基礎上,有了二階段協議,二階段協議的好處是添加了一個管理者角色。

 

 

很明顯,二階段協議通過將兩層變為三層,增加了中間的管理者角色,從而協調多個數
據源之間的關系,二階段提交協議分為兩個階段。

 

 

應用程序調用了事務管理器的提交方法,此后第一階段分為兩個步驟:
事務管理器通知參與該事務的各個資源管理器,通知他們開始准備事務。
資源管理器接收到消息后開始准備階段,寫好事務日志並執行事務,但不提交,然后將
是否就緒的消息返回給事務管理器(此時已經將事務的大部分事情做完,以后的內容耗時極
小)。
 

 

 

第二階段也分為兩個步驟:

 
事務管理器在接受各個消息后,開始分析,如果有任意其一失敗,則發送回滾命令,否
則發送提交命令。
各個資源管理器接收到命令后,執行(耗時很少),並將提交消息返回給事務管理器。
事務管理器接受消息后,事務結束,應用程序繼續執行。
為什么要分兩步執行?一是因為分兩步,就有了事務管理器統一管理的機會;二盡可能晚地提交事務,讓事務在提交前盡可能地完成所有能完成的工作,這樣,最后的提交階
段將是耗時極短,耗時極短意味着操作失敗的可能性也就降低。
同時,二階段提交協議為了保證事務的一致性,不管是事務管理器還是各個資源管
理器,每執行一步操作,都會記錄日志,為出現故障后的恢復准備依據。
 
缺點:
1 二階段提交協議的存在的弊端是阻塞,因為事務管理器要收集各個資源管理器的響應
消息,如果其中一個或多個一直不返回消息,則事務管理器一直等待,應用程序也被阻塞,
甚至可能永久阻塞。
 
2 兩階段提交理論的一個廣泛工業應用是 XA 協議。目前幾乎所有收費的商業數據庫都
支持 XA 協議。XA 協議已在業界成熟運行數十年,但目前它在互聯網海量流量的應用場景
中,吞吐量這個瓶頸變得十分致命,因此很少被用到。
 

三、 TCC 解決方案

 

1 TCC 介紹

TCC 是由支付寶架構師提供的一種柔性解決分布式事務解決方案,主要包括三個步驟
Try:預留業務資源/數據效驗
Confirm:確認執行業務操作
Cancel:取消執行業務操作
 

 

 

2 TCC 原理

 
TCC 方案在電商、金融領域落地較多。TCC 方案其實是兩階段提交的一種改進。其
將整個業務邏輯的每個分支顯式的分成了 Try、Confirm、Cancel 三個操作。Try 部分完成
業務的准備工作,confirm 部分完成業務的提交,cancel 部分完成事務的回滾。基本原理如
下圖所示

 

 

事務開始時,業務應用會向事務協調器注冊啟動事務。之后業務應用會調用所有服務
的 try 接口,完成一階段准備。之后事務協調器會根據 try 接口返回情況,決定調用 confirm
接口或者 cancel 接口。如果接口調用失敗,會進行重試。
微服務倡導服務的輕量化、易部署,而 TCC 方案中很多事務的處理邏輯需要應用自己
編碼實現,復雜且開發量大
 

3 TCC 的關鍵流程如下圖(以創建訂單和扣減庫存為例子)

 

 

4 TCC 優缺點

 

4.1TCC 優點:

 
讓應用自己定義數據庫操作的粒度,使得降低鎖沖突、提高吞吐量成為可能。4.2TCC 不足之處:
對應用的侵入性強。業務邏輯的每個分支都需要實現 try、confirm、cancel
三個操作,應用侵入性較強,改造成本高。
實現難度較大。需要按照網絡狀態、系統故障等不同的失敗原因實現不同的
回滾策略。為了滿足一致性的要求,confirm 和 cancel 接口必須實現冪等。
四、 分布式事務中間件解決方案
分布式事務中間件其本身並不創建事務,而是基於對本地事務的協調從而達到事務一致性
的效果。典型代表有:阿里的 GTS(https://www.aliyun.com/aliware/txc)、開源應用 LCN。
其實現原理如下: 

 

 

五、 什么是 LCN 框架

 

1 LCN 框架的由來

 
LCN 並不生產事務,LCN 只是本地事務的協調工
在設計框架之初的 1.0 ~ 2.0 的版本時,框架設計的步驟是如下的,各取其首字母得來
的 LCN 命名。
鎖定事務單元(lock)、確認事務模塊狀態(confirm)、通知事務(notify)2 LCN 框架相關資料
tx-lcn 官方地址:https://www.txlcn.org/
tx-lcn Github 地址:https://github.com/codingapi/tx-lcn
tx-lcn 服務下載地址:https://pan.baidu.com/s/1cLKAeE#list/path=%2F
tx-lcn 服務源碼地址:https://github.com/codingapi/tx-lcn/tree/master/tx-manager
 

六、 LCN 框架原理及執行步驟

 

1 LCN 的執行原理

 
1.1LCN 原理 

 

 

在上圖中,微服務 A,微服務 B,TxManager 事務協調器,都需要去 Eureka 中注冊服
務。Eureka 是用於 TxManager 與其他服務之間的相互服務發現。redis 是用於存放我們事務
組的信息以及補償的信息。然后微服務 A 與微服務 B 他們都需要去配置上我們 TxClient 的
包架構(代碼的包架構);來支持我們的 LCN 框架,以及他們的數據庫。
 

2 LCN 執行步驟

 

2.1創建事務組:

 
事務組是指的我們在整個事務過程中把各個節點(微服務)單元的事務信息存儲在一
個固定單元里。但這個信息並不是代表是事務信息,而是只是作為一個模塊的標示信息。
創建事務組是指在事務發起方開始執行業務代碼之前先調用 TxManager 創建事務組
對象,然后拿到事務標示 GroupId 的過程。

2.2添加事務組:

 
添加事務組是指參與方在執行完業務方法以后,將該模塊的事務信息添加通知給
TxManager 的操作。

2.3關閉事務組:

 
是指在發起方執行完業務代碼以后,將發起方執行結果狀態通知給 TxManager 的動
作。當執行完關閉事務組的方法以后,TxManager 將根據事務組信息來通知相應的參與模
塊提交或回滾事務。
 

2.4業務執行流程圖

 

 

 

 

如圖:假設服務已經執行到關閉事務組的過程,那么接下來作為一個模塊執行通知給
TxManager,然后告訴他本次事務已經完成。那么如圖中 Txmanager 下一個動作就是通過事
務組的 id,獲取到本次事務組的事務信息;然后查看一下對應有那幾個模塊參與,然后如果
是有 A/B/C 三個模塊;那么對應的對三個模塊做通知、提交、回滾。
那么提交的時候是提交給誰呢?
是提交給了我們的 TxClient 模塊。然后 TxCliient 模塊下有一個連接池,就是框架自定
義的一個連接池(如圖 DB 連接池);這個連接池其實就是在沒有通知事務之前一直占有着
這次事務的連接資源,就是沒有釋放。但是他在切面里面執行了 close 方法。在執行 close
的時候。如果需要(TxManager)分布式事務框架的連接。他被叫做“假關閉”,也就是沒有
關閉,只是在執行了一次關閉方法。實際的資源是沒有釋放的。這個資源是掌握在 LCN 的
連接池里的。
然后當 TxManager 通知提交或事務回滾的時候呢?
TxManager 會通知我們的 TxClient 端。然后 TxClient 會去執行相應的提交或回滾。提交
或回滾之后再去關閉連接。這就是 LCN 的事務協調機制。說白了就是代理 DataSource 的機
制;相當於是攔截了一下連接池,控制了連接池的事務提交。
 
 

八、 什么是 LCN 的事務補償機制

 

1 什么是補償事務機制?

LCN 的補償事務原理是模擬上次失敗事務的請求,然后傳遞給 TxClient 模塊然后再次
執行該次請求事務。
簡單的說:lcn 事務補償是指在服務掛機和網絡抖動情況下 txManager 無法通知事務單
元時。(通知不到也就兩種原因服務掛了和網絡出問題)在這種情況下 TxManager 會做一
個標示;然后返回給發起方。告訴他本次事務有存在沒有通知到的情況。
那么如果是接收到這個信息之后呢,發起方就會做一個標示,標示本次事務是需要補償
事務的。這就是事務補償機制。

2 為什么需要事務補償?

事務補償是指在執行某個業務方法時,本應該執行成功的操作卻因為服務器掛機或者網
絡抖動等問題導致事務沒有正常提交,此種場景就需要通過補償來完成事務,從而達到事務
的一致性。

3 補償機制的觸發條件?

當執行關閉事務組步驟時,若發起方接受到失敗的狀態后將會把該次事務識別為待補償
事務,然后發起方將該次事務數據異步通知給 TxManager。TxManager 接受到補償事務以后
先通知補償回調地址,然后再根據是否開啟自動補償事務狀態來補償或保存該次切面事務數
據。

九、 LCN 分布式事務框架應用

1 LCN 應用案例設計

1.1需求
創建三個服務分別為:springcloud-portal、springcloud-order、springcloud-inventory。在
springcloud-portal 服務中處理創建訂單的請求,然后分別請求 springcloud-order 以及
springcloud-inventory服務。在springcloud-order中插入一條訂單數據,在 springcloud-inventory
中對商品的數量做更新。
 
1.2使用技術
數據庫:Mysql
開發平台:SpringCloud+SpringBoot+MyBatis1.3數據庫設計
創建兩個數據庫分別為:sxt_orders,sxt_inventory。springcloud-order 操作 sxt_orders 庫,
springclooud-inventory 操作 sxt_inventory 庫
 
 
1.3.1sxt_orders 庫中的表設計
在 sxt_orders 庫中包含一個 tb_orders 表。表結構如下:
CREATE TABLE `tb_orders` (
`orderid` int(11) NOT NULL AUTO_INCREMENT,
`itemid` int(11) DEFAULT NULL,
`price` int(11) DEFAULT NULL,
PRIMARY KEY (`orderid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 

1.3.2sxt_inventory 庫中表設計

在 sxt_inventory 庫中包含一個 tb_inventory 表。表結構如下:
CREATE TABLE `tb_inventory` (
`inventoryid` int(11) NOT NULL AUTO_INCREMENT,
`itemid` int(11) DEFAULT NULL,
`itemnum` int(11) DEFAULT NULL,
PRIMARY KEY (`inventoryid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

2 創建服務

 

2.1創建項目

 
2.1.1springcloud-portal
pom 文件
 
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion><parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-portal</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies></dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId
>
</dependency>
<!-- 添加 Feign 坐標 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency></dependencies>
</project> 
 
 
 
 
 
application.properties 配置文件
spring.application.name=springcloud-portal
server.port=8080
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2
:8761/eureka/
2.1.2springcloud-order
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent><groupId>com.bjsxt</groupId>
<artifactId>springcloud-order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId
>
</dependency>
<!-- 添加 Feign 坐標 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mybatis 啟動器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId
><version>1.1.1</version>
</dependency>
<!-- mysql 數據庫驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 數據庫連接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
</dependencies>
</project>
application.properties 配置文件
spring.application.name=springcloud-order
server.port=8181
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
spring.datasource.driverClassName=com.mysql.jdbc.D
river
spring.datasource.url=jdbc:mysql://localhost:3306/
sxt_orders
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.Drui
dDataSource
mybatis.type-aliases-package=com.bjsxt.pojo
2.1.3springcloud-inventory
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement><dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId
>
</dependency>
<!-- 添加 Feign 坐標 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mybatis 啟動器 -->
<dependency><groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId
>
<version>1.1.1</version>
</dependency>
<!-- mysql 數據庫驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 數據庫連接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
</dependencies>
</project>
application.properties 配置文件
spring.application.name=springcloud-inventoryserver.port=8282
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2
:8761/eureka/
spring.datasource.driverClassName=com.mysql.jdbc.D
river
spring.datasource.url=jdbc:mysql://localhost:3306/
sxt_inventory
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.Drui
dDataSource
mybatis.type-aliases-package=com.bjsxt.pojo
2.2創建服務接口
2.2.1springcloud-order-service
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>2.2.2springcloud-inventory-service
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifactId
>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
修改 springcloud-inventory 服務的 pom 文件
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifact
Id>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改 springcloud-order 服務的 pom 文件
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改 springcloud-portal 服務的 pom 文件
<dependency><groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifact
Id>
<version>0.0.1-SNAPSHOT</version>
</dependency>
 
 
 
 
 
 
2.3實現業務
2.3.1實現添加訂單業務
2.3.1.1 添加 mapper
2.3.1.2 添加業務層
2.3.1.3 添加 controller
2.3.1.4 添加啟動類
2.3.1.5 在業務接口項目中添加 pojo
2.3.2實現修改庫存商品數量業務
2.3.2.1 添加 mapper
2.3.2.2 添加業務層
2.3.2.3 添加 controller
2.3.2.4 添加啟動類
2.3.2.5 在業務接口項目中添加 pojo
2.4實現 portal 中的創建訂單業務
2.4.1添加實現服務接口的接口
2.4.2添加 portalService 接口
2.4.3添加 controller
2.4.4添加啟動類
2.5測試
目前是不具備分布式事務處理能力的。3 使用 LCN 實現分布式事務處理
3.1下載 LCN 事務協調器

 

 

3.2配置事務協調器
3.2.1將事務協調器服務添加到 IDE 中
3.2.2配置事務協調器
#######################################txmanager-s
tart#################################################
#服務端口
server.port=8888
#tx-manager 不得修改
spring.application.name=tx-managerspring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/stati
c/
#######################################txmanager-e
nd#################################################
#zookeeper 地址
#spring.cloud.zookeeper.connect-string=127.0.0.1:2
181
#spring.cloud.zookeeper.discovery.preferIpAddress
= true
#eureka 地址
eureka.client.service-url.defaultZone=http://user:
123456@eureka1:8761/eureka/,http://user:123456@eureka
2:8761/eureka/
#######################################redis-start
#################################################
#redis 配置文件,根據情況選擇集群或者單機模式##redis 集群環境配置
##redis cluster
#spring.redis.cluster.nodes=127.0.0.1:7001,127.0.0
.1:7002,127.0.0.1:7003
#spring.redis.cluster.commandTimeout=5000
##redis 單點環境配置
#redis
#redis 主機地址
spring.redis.host=192.168.70.145
#redis 主機端口
spring.redis.port=6379
#redis 鏈接密碼
spring.redis.password=
spring.redis.pool.maxActive=10
spring.redis.pool.maxWait=-1
spring.redis.pool.maxIdle=5
spring.redis.pool.minIdle=0
spring.redis.timeout=0
#####################################redis-end####
######################################################################################LCN-start##
###############################################
#業務模塊與 TxManager 之間通訊的最大等待時間(單位:秒)
#通訊時間是指:發起方與響應方之間完成一次的通訊時間。
#該字段代表的是 Tx-Client 模塊與 TxManager 模塊之間的最
大通訊時間,超過該時間未響應本次請求失敗。
tm.transaction.netty.delaytime = 5
#業務模塊與 TxManager 之間通訊的心跳時間(單位:秒)
tm.transaction.netty.hearttime = 15
#存儲到 redis 下的數據最大保存時間(單位:秒)
#該字段僅代表的事務模塊數據的最大保存時間,補償數據會永
久保存。
tm.redis.savemaxtime=30
#socket server Socket 對外服務端口
#TxManager 的 LCN 協議的端口
tm.socket.port=9999#最大 socket 連接數
#TxManager 最大允許的建立連接數量
tm.socket.maxconnection=100
#事務自動補償 (true:開啟,false:關閉)
# 說明:
# 開啟自動補償以后,必須要配置
tm.compensate.notifyUrl 地址,僅當
tm.compensate.notifyUrl 在請求補償確認時返回 success 或者
SUCCESS 時,才會執行自動補償,否則不會自動補償。
# 關閉自動補償,當出現數據時也會
tm.compensate.notifyUrl 地址。
# 當 tm.compensate.notifyUrl 無效時,不影響 TxManager
運行,僅會影響自動補償。
tm.compensate.auto=false
#事務補償記錄回調地址(rest api 地址,post json 格式)
#請求補償是在開啟自動補償時才會請求的地址。請求分為兩種:
1.補償決策,2.補償結果通知,可通過通過 action 參數區分
compensate 為補償請求、notify 為補償通知。
#*注意當請求補償決策時,需要補償服務返回"SUCCESS"字符串以后才可以執行自動補償。
#請求補償結果通知則只需要接受通知即可。
#請求補償的樣例數據格式:
#{"groupId":"TtQxTwJP","action":"compensate","json
":"{\"address\":\"133.133.5.100:8081\",\"className\":
\"com.example.demo.service.impl.DemoServiceImpl\",\"c
urrentTime\":1511356150413,\"data\":\"C5IBLWNvbS5leGF
tcGxlLmRlbW8uc2VydmljZS5pbXBsLkRlbW9TZXJ2aWNlSW1wbAwS
BHNhdmUbehBqYXZhLmxhbmcuT2JqZWN0GAAQARwjeg9qYXZhLmxhb
mcuQ2xhc3MYABABJCo/cHVibGljIGludCBjb20uZXhhbXBsZS5kZW
1vLnNlcnZpY2UuaW1wbC5EZW1vU2VydmljZUltcGwuc2F2ZSgp\",
\"groupId\":\"TtQxTwJP\",\"methodStr\":\"public int
com.example.demo.service.impl.DemoServiceImpl.save()\
",\"model\":\"demo1\",\"state\":0,\"time\":36,\"txGro
up\":{\"groupId\":\"TtQxTwJP\",\"hasOver\":1,\"isComp
ensate\":0,\"list\":[{\"address\":\"133.133.5.100:889
9\",\"isCompensate\":0,\"isGroup\":0,\"kid\":\"wnlEJo
Sl\",\"methodStr\":\"public int
com.example.demo.service.impl.DemoServiceImpl.save()\
",\"model\":\"demo2\",\"modelIpAddress\":\"133.133.5.
100:8082\",\"channelAddress\":\"/133.133.5.100:64153\
",\"notify\":1,\"uniqueKey\":\"bc13881a5d2ab2ace89ae5d34d608447\"}],\"nowTime\":0,\"startTime\":1511356150
379,\"state\":1},\"uniqueKey\":\"be6eea31e382f1f0878d
07cef319e4d7\"}"}
#請求補償的返回數據樣例數據格式:
#SUCCESS
#請求補償結果通知的樣例數據格式:
#{"resState":true,"groupId":"TtQxTwJP","action":"n
otify"}
tm.compensate.notifyUrl=http://ip:port/path
#補償失敗,再次嘗試間隔(秒),最大嘗試次數 3 次,當超過
3 次即為補償失敗,失敗的數據依舊還會存在 TxManager 下。
tm.compensate.tryTime=30
#各事務模塊自動補償的時間上限(毫秒)
#指的是模塊執行自動超時的最大時間,該最大時間若過段會導
致事務機制異常,該時間必須要模塊之間通訊的最大超過時間。
#例如,若模塊 A 與模塊 B,請求超時的最大時間是 5 秒,則建
議改時間至少大於 5 秒。
tm.compensate.maxWaitTime=5000
#######################################LCN-end####
#############################################logging.level.com.codingapi=debug
3.3訪問 TX-Manager 事務協調器的管理頁面
訪問地址:http://ip:port 

 

 

3.4創建 TX-Client
3.4.1添加坐標
在所有需要處理分布式事務的微服務中增加下述依賴:為統一資源版本,使用
properties 統一管理版本信息。
<properties>
<lcn.last.version>4.1.0</lcn.last.version>
</properties>
<dependency><groupId>com.codingapi</groupId>
<artifactId>transaction-springcloud</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>tx-plugins-db</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
3.4.2實現接口
使用 LCN 做分布式事務管理時,服務需要知道事務協調器的 URL(客戶端與事務協
調器是通過 URL 來建立連接的)。我們需要實現一個接口 TxManagerTxUrlService,這個
接口實現類可以使用獨立應用定義,在微服務應用中引入
@Service
public class TxManagerTxUrlServiceImpl implements TxManagerTxUrlService {
@Value("${tm.manager.url}")
private String url;
@Override
public String getTxUrl() {
return url;
}
}
 
3.4.3創建事務客戶端項目 

 

 

 

3.4.4修改 pom 文件

 
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/
4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt</groupId>
<artifactId>tx-trans-manager-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<lcn.last.version>4.1.0</lcn.last.version>
</properties>
<dependencies>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>transaction-springcloud</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>tx-plugins-db</artifactId><version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
 

3.4.5在項目中創建 TxManagerTxUrlService 接口的實現類

@Service
public class TxManagerTxUrlServiceImpl implements
TxManagerTxUrlService {
@Value("${tm.manager.url}")
private String url;
@Override
public String getTxUrl() {
// "http://localhost:8888/tx/manager/";
return url;}
}

3.4.6完成項目的注入

 
將 tx-trans-manager-service 項目分別注入給 springcloud-inventory、springcloud-order、
springcloud-portal
 

3.4.7修改客戶端服務的配置文件

 
在客戶端服務的全局配置文件中增加下述配置:
# 定義事務協調器所在位置。根據具體環境定義其中的 IP 地址和端口。
tm.manager.url=http://127.0.0.1:8899/tx/manager/
 

3.5使用 LCN 提供的注解實現分布式事務處理

 
3.5.1@TxTransaction
3.5.1.1 在整個業務的事務代碼中添加注解@TxTransaction。
3.5.1.2 在 事 務 的 起 始 代 碼 中 的 @TxTransaction 注 解 中 添 加
isStart=true
 
3.5.2測試

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM