前言
随着互联化的蔓延,各种项目都逐渐向分布式服务做转换。如今微服务已经普遍存在,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生。
1.常见的一些分布式事务场景
案例 1:下订单和扣库存
案例 2:同步调用超时
案例 3:异步回调超时
案例 4:系统间状态不一致
案例 5:缓存和数据库不一致
案例 6:本地缓存节点间不一致
2.分布式事务理论
分布式事务被称为世界性的难题,目前分布式事务存在两大理论依据:CAP定律 BASE理论。
2.1CAP定律
这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。比如zookeeper保证了CP;
2.1.1一致性(C)
在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
2.1.2可用性(A)
在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
2.1.3分区容错性(P)
以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
2.2BASE理论
BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
2.2.1基本可用(Basically Available)
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。注意,这绝不等价于系统不可用。比如:
(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒
(2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面
2.2.2软状态(Soft State)
软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
2.2.3最终一致性(Eventually Consistent)
最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
2.3ACID(补充)
ACID 指如下内容 。
• A: Atomicity,原子性 。
• C: Consistency , 一致性。
• I: Isolation,隔离性。
• D: Durability,持久性。
具有 ACID 特性的数据库支持强一致性,强一致性代表数据库本身不会出现不一致, 每个事务都是原子的,或者成功或者失败,事物间是隔离的,互相完全不受影响,而且最终状态是持久落盘的。因此,数据库会从一个明确的状态过渡到另外一个明确的状态,中间的临时状态是不会出现的,如果出现也会及时地自动修复,因此是强一致的 。
3TX-LCN介绍
名词说明:
DTX:分布式事务 (Distributed Transaction)
LTX:本地事务 (Local Transaction)
RTX:远程事务 (Remote Transaction)(被调方本地事务)
TM: DTX协调服务器 (TXManager)
TC:DTX协调客户端 (TXClient)
事务发起方:一个用户请求下最先执行业务的服务
事务参与方:被事务发起方调用的服务
框架定位
LCN并不生产事务,LCN只是本地事务的协调工
TX-LCN定位于一款事务协调性框架,框架其本身并不操作事务,而是基于对事务的协调从而达到事务一致性的效果
- 事务模式
- TCC模式
TCC 分别对应 Try 、 Confirm 和 Cancel 三种操作,这三种操作的业务含义如下:
• Try:预留业务资源
• Confirm:确认执行业务操作
• Cancel:取消执行业务操作
在一个跨服务的业务操作中,首先通过 Try锁住服务中的业务资源进行资源预留,只有资源预留成功了,后续的操作才能正常进行。 Confirm 操作是在 Try 之后进行的操作,对Try 阶段锁定的资源进行业务操作。 Cancel 则是在所有操作失败时用于回滚。
相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。
3.1.2TXC模式
TXC(Taobao Transaction Constructor),命名来源于淘宝,实现原理是在执行SQL之前,先查询SQL的影响数据,然后保存执行的SQL快照信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库。
3.1.3LCN模式
LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,最后由协调器TM通知各参与方commit/rollback本地事务。该代理的连接将由LCN连接池管理。
LCN分别对应Lock、Confirm和notify三种操作,含义分别如下:
锁定事务单元(lock),确认事务模块状态(confirm),通知事务(notify)
LCN分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。因此该框架与其他第三方的框架兼容性强,支持所有的关系型数据库事务,支持多数据源,支持与第三方数据库框架一块使用(例如 sharding-jdbc),在使用框架的时候只需要添加分布式事务的注解即可,对业务的侵入性低。
3.2框架
兼容dubbo、springcloud框架,支持RPC框架拓展,支持各种ORM框架、NoSQL、负载均衡、事务补偿
3.3工作原理
LCN的工作原理图:(请参考https://www.txlcn.org/zh-cn/docs/principle/control.html)
核心步骤
1、创建事务组
是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。
2、加入事务组
添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。
3、通知事务组
是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。
3.4流程分析
假如有三个微服务A、B和C,服务A使用LCN模式实现,服务B使用TXC模式,服务C使用TCC模式。调用关系为Service A->Service B->Service C
首先有个事务协调器TM,它支持集群方式
执行流程:
①ServiceA执行的时候,首先会向TM发起创建分布式事务组;TM侧把事务组信息缓存在Redis中。
②接着调用service B,service B在执行操作sql之前会先查询并保存受影响的数据,然后执行操作,操作成功后并不提交,而是加入事务组。若失败则直接执行本地回滚,分布式事务也进行回滚。
③调用Service C时,需分别实现Try、confirm和Cancel对应的方法,servce C调用try方法进行操作,若成功加入事务组, 失败则执行对应的cancel函数。
④service A得到成功的响应后,执行完本地业务逻辑后将给TM发送Notify Group消息,并commit/rollback本地事务,TM接收到Notify Group消息后通知各参与方commit/rollback各自本地事务。
⑤若所有TC都返回执行成功,事务协调器TM则会通知各参与方。Service B收到以后删除保留的镜像数据,失败则利用镜像进行回滚并释放锁;Service C收到以后成功执行Confirm方法,否则执行Cancel方法。
3.5快速入门
3.5.1启动TM
①依赖
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
②增加注解
在主类上标注 @EnableTransactionManagerServer
③配置
spring.application.name=TransactionManager
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&serverTimezone=Asia/Shanghai
spring.datasource.username=test
spring.datasource.password=1234
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
3.5.2TC微服务
①依赖
<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>
②TC开启分布式事务注解
在启动类中添加@EnableDistributedTransaction
@SpringBootApplication
@EnableDiscoveryClient
@EnableDistributedTransaction
public class SpringServiceAApplication {
public static void main(String[] args) {
SpringApplication.run(SpringServiceAApplication.class, args);
}
}
业务方法配置:
LCN模式,
添加注解@LcnTransaction和@Transactional
TXC模式
添加注解@TxcTransaction和@Transactional
TCC模式
添加注解@TccTransaction和@Transactional
③配置
spring.application.name=txlcn-demo-spring-service-x
server.port=12102
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
## TODO 你的配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/txlcn-demo?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=test
spring.datasource.password=1234
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
## tx-manager 配置
tx-lcn.client.manager-address=127.0.0.1:8070
eureka.client.serviceUrl.defaultZone=http://localhost:12001/eureka/
3.6性能测试参数
(官方)
框架 | 模式 | 一致性 | 样本数 | KO | 平均时间(ms) | 最低时间(ms) | 最高时间(ms) | 90%时间(ms) | 95%时间(ms) | 吞吐量 |
dubbo | all | success | 43020 | 0 | 55.46231985123175 | 26 | 1052 | 52.0 | 66.0 | 358.61953984661557 |
dubbo | lcn | success | 46414 | 0 | 51.37234455121358 | 23 | 1231 | 52.0 | 65.0 | 386.89295300335095 |
dubbo | local | success | 67491 | 3253 | 35.26322028122323 | 9 | 444 | 116.0 | 160.0 | 562.6735141354097 |
dubbo | tcc | success | 48156 | 0 | 49.541095605946666 | 24 | 1175 | 53.0 | 62.0 | 401.4304649010929 |
dubbo | txc | success | 43123 | 0 | 55.338566426269196 | 26 | 1135 | 57.0 | 68.0 | 359.2206320910318 |
spring | all | success | 37473 | 0 | 63.68598724414947 | 26 | 1051 | 63.0 | 72.0 | 312.36350299251455 |
spring | lcn | success | 38941 | 613 | 61.027939703653814 | 7 | 611 | 62.0 | 75.0 | 324.6300696094369 |
spring | local | error | 49602 | 6816 | 47.26015080037109 | 7 | 525 | 147.0 | 164.0 | 413.28111981336446 |
spring | tcc | success | 38946 | 1369 | 60.97386124377325 | 7 | 1180 | 66.0 | 89.0 | 324.6852855356399 |
spring | txc | success | 36113 | 0 | 66.08238030626066 | 30 | 1152 | 64.0 | 73.0 | 301.0244483899739 |