TX-LCN分散式事務框架
隨著互聯化的蔓延,各種專案都逐漸向分散式服務做轉換。如今微服務已經普遍存在,本地事務已經無法滿足分散式的要求,由此分散式事務問題誕生。 分散式事務被稱為世界性的難題,目前分散式事務存在兩大理論依據:CAP定律 BASE理論。
官網地址:https://www.txlcn.org/zh-cn/
GitHun:https://github.com/yizhishang/tx-lcn/
在一個分散式系統下存在多個模組協調來完成一次業務。那麼就存在一次業務事務下可能橫跨多種資料來源節點的可能。TX-LCN將可以解決這樣的問題。
例如存在服務模組A 、B、 C。A模組是mysql作為資料來源的服務,B模組是基於redis作為資料來源的服務,C模組是基於mongo作為資料來源的服務。若需要解決他們的事務一致性就需要針對不同的節點採用不同的方案,並且統一協調完成分散式事務的處理。
方案:
若採用TX-LCN分散式事務框架,則可以將A模組採用LCN模式、B/C採用TCC模式就能完美解決。
TX-LCN 主要有兩個模組,Tx-Client(TC) Tx-Manager(TM). TC作為微服務下的依賴,TM是獨立的服務。
- 安裝TM需要依賴的中介軟體: JRE1.8+, Mysql5.6+, Redis3.2+
如果需要手動編譯原始碼, 還需要Git, Maven, JDK1.8+
- 建立MySQL資料庫, 名稱為: tx-manager
- 建立資料表
CREATE TABLE `t_tx_exception` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`transaction_state` tinyint(4) NULL DEFAULT NULL,
`registrar` tinyint(4) NULL DEFAULT NULL,
`remark` varchar(4096) NULL DEFAULT NULL,
`ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解決 1已解決',
`create_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
TM下載與配置
- 從歷史版本TM下載找到5.0.2.RELEASE的TM, 下載.
- 修改配置資訊
spring.application.name=tx-manager
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
# TxManager Host Ip
tx-lcn.manager.host=127.0.0.1
# TxClient連線請求埠
tx-lcn.manager.port=8070
# 心跳檢測時間(ms)
tx-lcn.manager.heart-time=15000
# 分散式事務執行總時間
tx-lcn.manager.dtx-time=30000
#引數延遲刪除時間單位ms
tx-lcn.message.netty.attr-delay-time=10000
tx-lcn.manager.concurrent-level=128
# TM後臺登陸密碼,預設值為codingapi
tx-lcn.manager.admin-key=123456
logging.level.com.codingapi=debug
#redis 主機
spring.redis.host=127.0.0.1
#redis 埠
spring.redis.port=6379
#redis 密碼
spring.redis.password=
# 開啟日誌,預設為false
tx-lcn.logger.enabled=true
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url}
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}
#
給出資訊都是預設值
關於詳細配置說明見TM配置- application.properties 載入順序如下:
0、命令列啟動引數指定
1、file:./config/(當前jar目錄下的config目錄)
2、file:./(當前jar目錄)
3、classpath:/config/(classpath下的config目錄)
4、classpath:/(classpath根目錄)
釋出的二進位制可執行Jar包含一個預設配置檔案(也就是4),可按需要覆蓋預設配置 - 把txlcn-tm的pom打包方式修改成
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 手動編譯TM,簡單指引
# git clone https://github.com/codingapi/tx-lcn.git & cd txlcn-tm
# mvn clean package '-Dmaven.test.skip=true'
target資料夾下,即為Ttxlcn-tm-5.0.2.RELEASE.jar
TC微服務模組
- 服務A作為DTX發起方,遠端呼叫服務B
工程說明
- finchley 父專案主要進行依賴管理
- common-config 可存方公共配置級工具
- common-eureka 服務註冊中心
- gateway-zuul 閘道器
- user-server 服務1
- money-server 服務2
忽略其他工程搭建步驟。
事務操作例項
user-server
提供遠端服務,money-server
通過fegin發現服務呼叫進行事務回滾。
這兩個服務需要加入依賴,如下:
<!-- springcloud 分散式事物 -->
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
依賴最好跟隨TM管理器版本,方式出現奇怪問題。
兩個工程的啟動類使用該@EnableDistributedTransaction
標記啟動分散式事務。
兩個工程properties需要加入事務管理器監控地址,如下:
#該配置根據TM打包時的配置進行
tx-lcn.client.manager-address=127.0.0.1:8070
在user-server
和money-server
插入資料,server例項:
/**
* user-server
* @Auhotr:SimpleWu
* @TxTransaction 使用該註解啟動分散式事務
* @Transactional 同時使用spring事務開啟本地事務
* 插入一個使用者
*/
@Override
@TxTransaction
@Transactional
public int insertUser(Map<String, Object> map) {
userServerMapper.insert(map);
return "insertUser success";
}
//fegin呼叫user-server服務
@Autowired
private UserFegin userFegin;
//對money表操作mapper
@Autowired
private MoneyServerMapper moneyServerMapper;
/**
* user-server
* @Auhotr:SimpleWu
* @TxTransaction 使用該註解啟動分散式事務
* @Transactional 同時使用spring事務開啟本地事務
* 插入一個使用者
*/
@Override
@TxTransaction
@Transactional
public String insert() {
String userId = UUID.randomUUID().toString();
Map<String,Object> param = new HashMap<>();
param.put("ID",userId);
param.put("USER_ID",userId);
param.put("MONEY",100);
param.put("USERPASS","12321321");
//先呼叫遠端服務測試事務回滾
System.out.println( userFegin.hello("張三","12321321",userId));
int i = 0 / 0;
moneyServerMapper.insert(param);
return "success " + param;
}
啟動順序:
- 部署Redis
- 部署TM的Jar包
- 部署Eureka服務註冊中心
- 部署user-server服務
- 部署money-server服務
- 忽略閘道器等.....
訪問money-server服務
:http://localhost:13000/hello
呼叫 insert();
int i = 0 / 0;
該行程式碼發生異常,UserFegin為user-server
遠端放服務呼叫後列印"insertUser success"
代表呼叫成功,如果分散式事務沒有效果,那麼遇見該異常遠端方不會進行回滾。
在本次測試是回滾成功的,就不貼圖了,親自嘗試才能體會到,那種感覺。
然後刪除money-server
中刪除int i = 0 / 0;
重新啟動。
再次呼叫http://localhost:13000/hello
呼叫 insert(),成功插入兩條資料。
訪問:http://localhost:7970
進入TxManager系統後臺,登入密碼是我們設定的123456
。裡面可以看到配置資訊,以及異常資訊日誌,系統日誌。
該篇案例原始碼與工具見:https://github.com/450255266/open-doubi