目录
Spring Cloud Alibaba专栏目录(点击进入…)
Spring Cloud Alibaba Seata(分布式事务)
Spring Cloud Alibaba Seata(分布式事务)
分布式CAP定理(三个指标)
(1)Consistency(一致性)
用户访问分布式系统中的任意节点,得到的数据必须一致。
(2)Avallabiry(可用性)
用户访问集群中的任意健康节点,必须能得到响应,而不是超时或拒绝。
(3)Partition tolerance(分区容错性)
分区:因为网络故障或其他原因导致分布式系统中的部分节点与其他节点失去连接,形成独立分区
容错:在集群出现分区时,整个系统也要持续对外提供服务
分布式系统无法同时满足这三个指标,这个结论叫做CAP定理
BASE理论
BASE理论是对CAP的一种解决思路,包含三个思想:
(1)Basically Available(基本可用)
分布式系统在出现故障时,允许损失部分的可用性,即保证核心可用
(2)Soft State(软状态)
在一定时间内,允许出现中间状态,比如临时的不一致状态
(3)Eventually Consistent(最终一致性)
虽然无法保证一致性,但是在软状态结束后,最终达到数据一致
而分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理和BASE理论:
模式 | 描述 |
---|---|
AP模式 | 各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致 |
CP模式 | 各子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态 |
分布式事务模型
解决分布式事务,各个子系统之间必须能感知到彼此的事务状态,才能保证状态一致,因此需要一个事务协调者来协调每一个事务的参与者(子系统事务)
事务介绍
(1)本地事务
大多数场景下,应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务(Local Transaction)。本地事务的ACID特性是数据库直接提供支持
本地事务要求只有一个数据库连接Connection,通过这个连接Connection对数据库事务进行开启begin、提交commit来保证整个代码的事务
伪代码如下:
Connection conn = getConnection(); //获取数据库连接
conn.setAutoCommit(false); //开启事务
try {
//...执行增删改查sql
conn.commit(); //提交事务
} catch (Exception e) {
conn.rollback();//事务回滚
} finally {
conn.close();//关闭链接
}
Spring通过AOP的方式对数据库事务进行了整合,使平时在解决本地事务时,只需要加上@Transactional注解即可很方便控制本地事务
(2)分布式事务
对于微服务架构,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。这就涉及到到了分布式事务。分布式事务需要保证在多个数据库连接下,代码要么全部成功,要么全部失败。
本质上来说,分布式事务就是操作多个数据库连接时,也能保证数据要么一起修改成功,要么一起失败!为了保证不同资源服务器的数据一致性
分布式事务的出现场景:
(1)跨库事务
一个应用某个功能需要操作多个库
(2)分库分表
一般开发人员都会使用一些数据库中间件来降低sql操作的复杂性。
如,对于sql:insert into user(id,name) values (1,“张三”),(2,“李四”)。这条sql是操作单库的语法,单库情况下,可以保证事务的一致性。
但是由于现在进行了分库分表,开发人员希望将1号记录插入分库1,2号记录插入分库2。所以数据库中间件要将其改写为2条sql,分别插入两个不同的分库,此时要保证两个库要不都成功,要不都失败,因此就面临着分布式事务的问题
(3)微服务
一个接口会调用很多服务,每个服务都有独立的数据库连接
Seata(分布式事务)
Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案
官方下载:https://seata.io/zh-cn/blog/download.html
Seata角色(三种)
其中,TC为单独部署的Server服务端,TM和RM为嵌入到应用中的Client客户端
1.TC (Transaction Coordinator,事务协调者)
维护全局和分支事务的状态,驱动全局事务提交或回滚。
2.TM(Transaction Manager,事务管理器)
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
3.RM(Resource Manager,资源管理器)
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
分布式事务的生命周期
1.事务管理器TM请求 事务协调者TC开启一个全局事务。TC会生成一个XID作为该全局事务的编号。XID会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。TM是一个事务的发起者,可以是事务方法的入口
2.客户端的资源管理器RM请求TC将本地事务注册为全局事务的分支事务,通过全局事务的XID进行关联
3.TM请求TC告诉XID对应的全局事务是进行提交还是回滚
4.TC驱动RM们将XID对应的自己的本地事务进行提交还是回滚
Seata设计思路
Seata的AT模式的核心是对业务无侵入,是一种改进后的两阶段提交,其设计思路如下:
①第一阶段:RM端提交本地事务,生成undo日志记录,释放本地锁和连接资源。并向TC注册分支事务,通过全局事务的XID进行关联。
②第二阶段:完全异步
(1)分布式事务操作成功,则TC通知RM异步删除undolog
(2)分布式事务操作失败,则TM向TC发送回滚请求,RM收到协调器TC发来的回滚请求,通过XID和Branch ID找到相应的回滚日志记录,通过回滚记录生成反向的更新SQL并执行,以完成分支的回滚
设计亮点以及存在的问题
设计亮点:
(1)应用层基于SQL解析实现了自动补偿,从而最大程度的降低业务侵入性
(2)将分布式事务中TC(事务协调者)独立部署,负责事务的注册、回滚
(3)通过全局锁实现了写隔离与读隔离
存在的问题:
(1)性能损耗
由于Seata在解决分布式事务时,需要多次与TC通讯,每次都需要一次远程通讯RPC,而且是同步的。还要写undoLog日志,每条写SQL都会增加这么多开销,粗略估计会增加5倍响应时间
(2)性价比
如果仅有极少的请求会失败,需要触发回滚。在使用了Seata解决分布式事务后,为了极少的交易回滚,需要将大部分的成功交易的响应时间增加5倍,这样的代价有待考量。
(3)死锁问题
Seata的引入全局锁会额外增加死锁的风险,但如果出现死锁,会不断进行重试,最后靠等待全局锁超时,这种方式并不优雅,也延长了对数据库锁的占有时间
Seata的DB模式配置
Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。由于Seata的事务协调者TC是单独配置的,所以在使用Seata时需要先配置TC,然后再配置客户端RM和TM
①TC环境配置
②客户端RM和TM配置
TC(Server端)存储模式(store.mode)现有file、db、redis三种
模式 | 描述 |
---|---|
file | 无需改动,直接启动即可 |
db | 高可用模式,全局事务会话信息通过db共享,相应性能差些 |
redis | Seata-Server 1.3及以上版本支持,性能较高,存在事务信息丢失风险,请提前配置合适当前场景的redis持久化配置 |
四种模型对比
XA模式 | AT模式 | TCC模式 | SAGA模式 | |
---|---|---|---|---|
一致性 | 强一致性 | 弱一致 | 弱一致 | 最终一致 |
隔离性 | 完全隔离 | 全局锁隔离 | 资源预留隔离 | 无隔离 |
代码侵入 | 无 | 无 | 有,要编写三个接口 | 有,要编写状态机和补偿业务 |
性能 | 差 | 好 | 非常好 | 非常好 |
场景 | 对一致性、隔离性有高业务的需求 | 基于关系型数据库的大多数分布式事务场景 | 1、对性能要求较高的业务。2、有非关系型数据库要参与的业务 | 1、业务流程长、业务流程多。2、参与者包含其他公司或遗留系统服务,无法提供TCC模式要求的三个接口 |