分布式事务【搭建事务管理器】
1. CAP 定理和 BASE 理论
1.1. CAP(Consistency, Availability, Partition tolerance)
CAP原则又称CAP定理,它描述了分布式系统中的三个基本属性:
- 一致性(Consistency) :数据在多个副本之间能够保持一致的特性。即,无论数据被读取或写入哪个副本,所有副本上的数据都应该是相同的。
- 可用性(Availability) :系统提供的服务一直处于可用的状态,每次请求都能获得正确的响应。即,系统应该保证在任何时候都能及时响应请求,无论系统是否正在处理其他请求或是否发生故障。
- 分区容错性(Partition tolerance) :分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。即,系统应该能够容忍网络分区,即使部分节点之间的通信被中断,系统仍然能够继续运行并提供服务。
注意:CAP原则指出,在分布式系统中,这三个属性不能同时满足,最多只能同时满足其中的两个。这是因为当网络分区发生时,系统需要在一致性和可用性之间进行权衡。如果选择保持一致性(C),那么在分区发生时,系统可能需要拒绝一些请求以保证数据的一致性,这会影响系统的可用性(A)。如果选择保持可用性(A),那么在分区发生时,系统可能会接受并处理一些可能导致数据不一致的请求。
1.2. BASE(Basically Available, Soft-state, Eventually Consistent)
BASE理论是对CAP中一致性和可用性权衡的结果,它起源于对大规模互联网系统分布式实践的总结,并基于CAP定理逐渐演化而来。BASE理论包括三个核心要素:
- 基本可用(Basically Available) :系统应该能够在大多数情况下正常工作并提供服务,即使发生了一些故障或错误。这意味着系统应该能够容忍一些非关键性的故障,并在故障发生时保持部分功能的可用性。
- 软状态(Soft-state) :允许系统中的数据存在中间状态(即CAP理论中的数据不一致),并认为该中间状态不会影响系统的整体可用性。即,系统可以允许数据在不同节点之间存在一定的延迟或不一致性,但最终应该能够达到一致的状态。
- 最终一致性(Eventually Consistent) :强调系统中所有的数据副本在经过一段时间的同步后,最终能够达到一个一致的状态。这与强一致性不同,强一致性要求在任何时刻,系统中的所有���据副本都应该是相同的。而最终一致性则允许在短时间内存在不一致性,但系统应该能够保证在最终状态下所有副本的数据都是一致的。
2. 搭建分布式事务管理器
下面我们来搭建一下 tx-lcn 这个分布式事务框架。在这个框架中,它将事务管理器称为 协调者
,也叫 tm
,每个参与事务的叫做参与者,也叫 tc
。下面我们就来简述一下这两者的搭建,另外这个是它的官网:CodingApi | CodingAPI is an open source organization.
2.1. TM 搭建
首先导入依赖,我们的项目是基于 springboot 来搭建的,另外 tx-lcn 使用到了数据库和 redis,其中数据库需要我们自己导入,因为数据库有很多,而 redis 只有一个。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
然后我们需要创建一个数据库,以及一张表,建库建表语句 tx-lcn 的 jar 包也有,官网也有,这里我就直接引用 jar 包中的语句,他使用的是 mysql。
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;
然后就是配置文件了,这个配置文件经过我的尝试,发现 yml 的配置文件,tx-lcn 读取不了,只能读取 properties 的配置文件。配置可参考官网的配置,下面是我的配置:
# tx-manager 服务端口
server.port=23456
spring.application.name=tx-manager
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimeZone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=12345
spring.jpa.database-platform=org.hibernate.dialect.MySQL57Dialect
spring.jpa.hibernate.ddl-auto=update
spring.redis.host=localhost
spring.redis.database=0
spring.redis.port=6379
tx-lcn.logger.enabled=true
tx-lcn.logger.driver-class-name=com.mysql.cj.jdbc.Driver
tx-lcn.logger.jdbc-url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8&serverTimeZone=UTC&useSSL=false
tx-lcn.logger.username=root
tx-lcn.logger.password=12345
# TC 连接端口
tx-lcn.manager.port=8070
tx-lcn.manager.admin-key=12345
tx-lcn.manager.ex-url-enabled=false
tx-lcn.manager.seq-len=12
注意上面的 server.port
和 tx-lcn.manager.port
这两个端口的作用可不一样,前者是供浏览器那样的用户终端访问的,有 UI,可以通过 localhost:port
来访问,查看 TC 的情况。后者是 TC 连接以及传输数据的端口。
最后在启动类上加上 @EnableTransactionManagerServer
注解即可。
2.2. TC 搭建
首先是安装依赖:
<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>
然后是配置文件,添加下面的配置:
tx-lcn:
client:
manager-address: localhost:8070
然后在你的事务方法上加上下面的注解。
@Transactional
@LcnTransaction
最后在启动类上添加 @EnableDistributedTransaction
注解即可。
2.3. 测试
同时使用熔断器和分布式事务 @LcnTransaction
,经过测试,两个事务方法,如果后者出现了错误,两者都会触发回滚。熔断器也能正常触发。不过有些情况下熔断器和分布式事务一起使用会有问题,后面我们再细说。
@Transactional
@LcnTransaction
@HystrixCommand(fallbackMethod = "fallback", commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
})
转载自:https://juejin.cn/post/7385776177716936730