一、簡介
LCN分布式事務(wù)框架其本身并不創(chuàng)建事務(wù),而是基于對本地事務(wù)的協(xié)調(diào)從而達到事務(wù)一致性的效果蜜另。
LCN5.0.2有3種模式,分別是LCN模式嫡意,TCC模式举瑰,TXC模式
LCN模式:
LCN模式是通過代理Connection的方式實現(xiàn)對本地事務(wù)的操作,然后在由TxManager統(tǒng)一協(xié)調(diào)控制事務(wù)蔬螟。當本地事務(wù)提交回滾或者關(guān)閉連接時將會執(zhí)行假操作此迅,該代理的連接將由LCN連接池管理。
該模式的特點:
- 該模式對代碼的嵌入性為低旧巾。
- 該模式僅限于本地存在連接對象且可通過連接對象控制事務(wù)的模塊耸序。
- 該模式下的事務(wù)提交與回滾是由本地事務(wù)方控制,對于數(shù)據(jù)一致性上有較高的保障鲁猩。
- 該模式缺陷在于代理的連接需要隨事務(wù)發(fā)起方一共釋放連接坎怪,增加了連接占用的時間。
TCC模式:
TCC事務(wù)機制相對于傳統(tǒng)事務(wù)機制(X/Open XA Two-Phase-Commit)廓握,其特征在于它不依賴資源管理器(RM)對XA的支持搅窿,而是通過對(由業(yè)務(wù)系統(tǒng)提供的)業(yè)務(wù)邏輯的調(diào)度來實現(xiàn)分布式事務(wù)。主要由三步操作隙券,Try: 嘗試執(zhí)行業(yè)務(wù)男应、 Confirm:確認執(zhí)行業(yè)務(wù)、 Cancel: 取消執(zhí)行業(yè)務(wù)娱仔。
該模式的特點:
- 該模式對代碼的嵌入性高沐飘,要求每個業(yè)務(wù)需要寫三種步驟的操作。
- 該模式對有無本地事務(wù)控制都可以支持使用面廣牲迫。
- 數(shù)據(jù)一致性控制幾乎完全由開發(fā)者控制薪铜,對業(yè)務(wù)開發(fā)難度要求高众弓。
TXC模式:
TXC模式命名來源于淘寶恩溅,實現(xiàn)原理是在執(zhí)行SQL之前隔箍,先查詢SQL的影響數(shù)據(jù),然后保存執(zhí)行的SQL快走信息和創(chuàng)建鎖脚乡。當需要回滾的時候就采用這些記錄數(shù)據(jù)回滾數(shù)據(jù)庫蜒滩,目前鎖實現(xiàn)依賴redis分布式鎖控制。
該模式的特點:
- 該模式同樣對代碼的嵌入性低奶稠。
- 該模式僅限于對支持SQL方式的模塊支持俯艰。
- 該模式由于每次執(zhí)行SQL之前需要先查詢影響數(shù)據(jù),因此相比LCN模式消耗資源與時間要多锌订。
- 該模式不會占用數(shù)據(jù)庫的連接資源竹握。
二、原理
核心步驟
1.創(chuàng)建事務(wù)組
是指在事務(wù)發(fā)起方開始執(zhí)行業(yè)務(wù)代碼之前先調(diào)用TxManager創(chuàng)建事務(wù)組對象辆飘,然后拿到事務(wù)標示GroupId的過程啦辐。
2.添加事務(wù)組
添加事務(wù)組是指參與方在執(zhí)行完業(yè)務(wù)方法以后,將該模塊的事務(wù)信息添加通知給TxManager的操作蜈项。
3.關(guān)閉事務(wù)組
是指在發(fā)起方執(zhí)行完業(yè)務(wù)代碼以后芹关,將發(fā)起方執(zhí)行結(jié)果狀態(tài)通知給TxManager的動作。當執(zhí)行完關(guān)閉事務(wù)組的方法以后紧卒,TxManager將根據(jù)事務(wù)組信息來通知相應(yīng)的參與模塊提交或回滾事務(wù)侥衬。
事務(wù)控制原理
LCN事務(wù)控制原理是由事務(wù)模塊TxClient下的代理連接池與TxManager的協(xié)調(diào)配合完成的事務(wù)協(xié)調(diào)控制。
TxClient的代理連接池實現(xiàn)了javax.sql.DataSource接口跑芳,并重寫了close方法轴总,事務(wù)模塊在提交關(guān)閉以后TxClient連接池將執(zhí)行"假關(guān)閉"操作,等待TxManager協(xié)調(diào)完成事務(wù)以后在關(guān)閉連接博个。
對于代理連接池的優(yōu)化
自動超時機制怀樟,任何通訊都有最大超時限制,參與模塊在等待通知的狀態(tài)下也有最大超時限制坡倔,當超過時間限制以后事務(wù)模塊將先確認事務(wù)狀態(tài)漂佩,然后再決定執(zhí)行提交或者回滾操作,主要為了給最大資源占用時間加上限制罪塔。
智能識別創(chuàng)建不同的連接 對于只讀操作投蝉、非事務(wù)操作LCN將不開啟代理功能,返回本地連接對象征堪,對于補償事務(wù)的啟動方將開啟回滾連接對象瘩缆,執(zhí)行完業(yè)務(wù)以后馬上回滾事務(wù)。
LCN連接重用機制 當模塊在同一次事務(wù)下被重復執(zhí)行時佃蚜,連接資源會被重用庸娱,提高連接的使用率着绊。
事務(wù)補償機制
為什么需要事務(wù)補償?
事務(wù)補償是指在執(zhí)行某個業(yè)務(wù)方法時熟尉,本應(yīng)該執(zhí)行成功的操作卻因為服務(wù)器掛機或者網(wǎng)絡(luò)抖動等問題導致事務(wù)沒有正常提交归露,此種場景就需要通過補償來完成事務(wù),從而達到事務(wù)的一致性斤儿。
補償機制的觸發(fā)條件剧包?
當執(zhí)行關(guān)閉事務(wù)組步驟時,若發(fā)起方接受到失敗的狀態(tài)后將會把該次事務(wù)識別為待補償事務(wù)往果,然后發(fā)起方將該次事務(wù)數(shù)據(jù)異步通知給TxManager疆液。TxManager接受到補償事務(wù)以后先通知補償回調(diào)地址,然后再根據(jù)是否開啟自動補償事務(wù)狀態(tài)來補償或保存該次切面事務(wù)數(shù)據(jù)陕贮。
補償事務(wù)機制堕油?
LCN的補償事務(wù)原理是模擬上次失敗事務(wù)的請求,然后傳遞給TxClient模塊然后再次執(zhí)行該次請求事務(wù)肮之。
模擬場景演示
若存在事務(wù)發(fā)起方掉缺、參與方A、參與方B局骤。調(diào)用關(guān)系圖如下
那么他們正常執(zhí)行業(yè)務(wù)的時序圖為:
若參與方B出現(xiàn)異常攀圈,那么他們的業(yè)務(wù)時序圖為:
若他們的調(diào)用關(guān)系是這樣的情況
此時發(fā)生參與方B出現(xiàn)異常時他們的時序圖為:
三、使用
環(huán)境:
SpringBoot 2.0.4
SpringCloud(Eureka+Gateway) Finchley.SR3
MySQL 5.7
Redis
LCN5.0.2
準備:
3.1搭建好Redis和MySQL
SQL建表語句(在txlcn-tm模塊的resource目錄下)
/*
Navicat Premium Data Transfer
Source Server : local
Source Server Type : MySQL
Source Server Version : 100309
Source Host : localhost:3306
Source Schema : tx-manager
Target Server Type : MySQL
Target Server Version : 100309
File Encoding : 65001
Date: 29/12/2018 18:35:59
*/
CREATE DATABASE IF NOT EXISTS tx-manager
DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE tx-manager
;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- Table structure for t_tx_exception
DROP TABLE IF EXISTS t_tx_exception
;
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,
ex_state
tinyint(4) NULL DEFAULT NULL COMMENT '0 待處理 1已處理',
remark
varchar(10240) NULL DEFAULT NULL COMMENT '備注',
create_time
datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (id
) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
3.2下載源碼并編譯
源碼下載地址:https://github.com/codingapi/tx-lcn
工程目錄
修改txlcn-tm的配置文件application.properties
####################### 服務(wù) ############################################
spring.application.name=TransactionManager
server.port=7970
####################### 數(shù)據(jù)庫 ############################################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://47.92.145.192:3306/scm_transaction?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
spring.datasource.username=db_user2
spring.datasource.password=db_pass
驗證連接是否有效峦甩。此參數(shù)必須設(shè)置為非空字符串赘来,下面三項設(shè)置成true才能生
spring.datasource.validationQuery=SELECT 1
指明連接是否被空閑連接回收器(如果有)進行檢驗.如果檢測失敗,則連接將被從池中去除.
spring.datasource.testWhileIdle=true
指明是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接并嘗試取出另一個
spring.datasource.testOnBorrow=true
指明是否在歸還到池中前進行檢驗
spring.datasource.testOnReturn=false
以下可省略
初始化大小,最小凯傲,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=10
spring.datasource.maxActive=1000
配置獲取連接等待超時的時間
spring.datasource.maxWait=60000
配置間隔多久才進行一次檢測犬辰,檢測需要關(guān)閉的空閑連接,單位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
配置一個連接在池中最小生存的時間冰单,單位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
打開PSCache幌缝,并且指定每個連接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
配置監(jiān)控統(tǒng)計攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計诫欠,'wall'用于防火墻
spring.datasource.filters=stat,wall,log4j
通過connectProperties屬性來打開mergeSql功能涵卵;慢SQL記錄
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000;druid.stat.logSlowSql=true
合并多個DruidDataSource的監(jiān)控數(shù)據(jù)
spring.datasource.useGlobalDataSourceStat=true
spring.datasource.WebStatFilter.exclusions=".js,.gif,.jpg,.png,.css,.ico,/druid/*"
spring.datasource.stat-view-servlet.login-username=admin
spring.datasource.stat-view-servlet.login-password=admin
####################### 數(shù)據(jù)庫方言 ############################################
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
第一次運行可以設(shè)置為: create, 為TM創(chuàng)建持久化數(shù)據(jù)庫表
spring.jpa.hibernate.ddl-auto=update
####################### Redis ############################################
spring.redis.host=47.92.145.192
spring.redis.port=6379
spring.redis.password=WZTH@dev123
####################### 事務(wù) ############################################
TM監(jiān)聽IP. 默認為 127.0.0.1
tx-lcn.manager.host=127.0.0.1
TM監(jiān)聽Socket端口. 默認為 ${server.port} - 100
tx-lcn.manager.port=8070
心跳檢測時間(ms). 默認為 300000
tx-lcn.manager.heart-time=300000
分布式事務(wù)執(zhí)行總時間(ms). 默認為36000
tx-lcn.manager.dtx-time=8000
參數(shù)延遲刪除時間單位ms 默認為dtx-time值
tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}
事務(wù)處理并發(fā)等級. 默認為機器邏輯核心數(shù)5倍
tx-lcn.manager.concurrent-level=160
TM后臺登陸密碼,默認值為codingapi
tx-lcn.manager.admin-key=123456
分布式事務(wù)鎖超時時間 默認為-1荒叼,當-1時會用tx-lcn.manager.dtx-time的時間
tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}
雪花算法的sequence位長度轿偎,默認為12位.
tx-lcn.manager.seq-len=12
異常回調(diào)開關(guān)被廓。開啟時請制定ex-url
tx-lcn.manager.ex-url-enabled=false
事務(wù)異常通知(任何http協(xié)議地址坏晦。未指定協(xié)議時,為TM提供內(nèi)置功能接口)。默認是郵件通知
tx-lcn.manager.ex-url=/provider/email-to/306509906@qq.com
注意:個人修改了數(shù)據(jù)庫的名稱昆婿,和用戶名密碼球碉,根據(jù)自己的實際情況修改
txlcn-tm的pom修改,放開配置
注掉配置
最后使用maven編譯仓蛆,去掉test睁冬,否則編譯很慢
3.3啟動txlcn-tm模塊
不知道怎么啟動的可以自行查閱Springboot運行方式
啟動后打開后臺地址http://localhost:7970,初始密碼是codingapi多律,我這里改成了123456
登陸后
3.4項目配置
pom引用
<!-- LCN -->
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
配置文件增加事務(wù)管理中心地址
LCN
tx-lcn:
client:
manager-address: 127.0.0.1:8070
logger:
enabled: true
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://47.92.145.192:3306/scm_transaction?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
username: db_user2
password: db_pass
Consumer痴突、Provider1、Provider2啟動類增加注解
@EnableDistributedTransaction // 啟用分布式事務(wù)
在Priovider1狼荞、Provider2要執(zhí)行的方法上增加注解
@LcnTransaction //分布式事務(wù)注解
@Transactional //本地事務(wù)注解
最后運行 驗證即可
原文鏈接:https://blog.csdn.net/ningjiebing/java/article/details/89948050