一、数据库事务ACID特性
基础概念:事务ACID
- A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失 败的情况。
- C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转100元, 转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出100元,李四账户没有增加100元这就出现了数 据错误,就没有达到一致性。
- I(Isolation):隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事 务不能看到其他事务运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题。
- D(Durability):持久性,事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。
二、什么是分布式事务
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
三、分布式事务典型场景
1、多服务
随着互联网快速发展,微服务,SOA等服务架构模式正在被大规模的使用,会出现很多分布式事务问题如下:
2、多数据源
2.1 跨库
跨库事务指的是,一个应用某个功能需要操作多个库,如下图:
2.2 分库分表
通常一个库数据量比较大或者预期未来的数据量比较大,都会进行水平拆分,也就是分库分表。如下图,将订单数据库拆分成了4个库:
小结:上述讨论的分布式事务场景中,无一例外的都直接或者间接的操作了多个数据库。如何保证事务的ACID特性,对于分布式事务实现方案而言,是非常大的挑战。同时,分布式事务实现方案还必须要考虑性能的问题,如果为了严格保证ACID特性,导致性能严重下降,那么对于一些要求快速响应的业务,是无法接受的。
四、分布式事务基础理论
随着互联化的蔓延,各种项目都逐渐向分布式服务做转换。如今微服务已经普遍存在,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生。 分布式事务被称为世界性的难题,目前分布式存在两大理论依据:CAP定律 BASE理论。
1、CAP定律
这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
-
一致性(C)
对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。
-
可用性(A)
非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。
-
分区容错性(P)
当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。
在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。
对于CP来说,放弃可用性,追求一致性和分区容错性,我们的zookeeper其实就是追求的强一致。
对于AP来说,放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,后面的BASE也是根据AP来扩展。
2、BASE理论
BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
-
基本可用
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性—-注意,这绝不等价于系统不可用。比如:
(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒
(2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面
-
软状态
软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
-
最终一致性
最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
3、酸碱平衡
ACID (酸)能够保证事务的强一致性,即数据是实时一致的。
BASE(碱) 要求的最终一致性
目标 | 说明 | 场景 |
---|---|---|
强一致(ACID) | 参与事务的分支全部一起行动,单个子事务操作不完全提交,等待最终提交<br />当事务完成后,后续其它的访问都会返回最新的更新过的值。 | 比如下单扣优惠券,需要强一致性,不然优惠券可以用多次 |
最终一致(BASE) | 参与事务的分支可以单独行动,单个子事务操作可以先行提交不保证后续的访问,<br />能够立刻返回最新的值,不确定多久之后可以访问到,但是需要保证过一段时间之后,最终能够访问到最新的值。 | 比如下单送积分,积分可以晚一点再送,不会影响主流程 |
强一致性
最终一致性
五、分布式事务协议
1、2PC
1.1 流程
1.2 优缺点
优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持(XA)。
缺点:
- 单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
- 同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
- 数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
2、3PC
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC
在 2PC
的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当 参与者
各种原因未收到 协调者
的commit请求后,会对本地事务进行abort,不会一直阻塞等待,解决了 2PC
的单点故障问题,但 3PC
还是没能从根本上解决数据一致性的问题。
2.1 流程
CanCommit:协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。
PreCommit:协调者
向所有 参与者
发送 PreCommit
命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回 Yes
响应,进入最终commit阶段。一旦参与者中有向协调者发送了 No
响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送 abort
请求,参与者接受abort命令执行事务的中断。
DoCommit: 在前两个阶段中所有参与者的响应反馈均是 YES
后,协调者向参与者发送 DoCommit
命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送 abort
请求命令,执行事务的中断
2.2 优缺点
- 优点:
1、引入超时机制。解决了事务管理器突然宕机导致资源一直处于阻塞的问题
2、多了一次询问阶段。防止个别参与者不正常的情况下,其他参与者都执行了事务,锁定资源。
- 缺点:
1、 3PC
用超时机制,同步阻塞问题,但与此同时却多了一次网络通信,性能上反而变得更差,也不太推荐。
2、没有解决数据不一致的问题
六、Seata
1、Seata介绍
官网:https://seata.io/zh-cn/docs/overview/what-is-seata.html
概念:Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
- AT模式:提供无侵入自动补偿的事务模式
- XA模式:支持已实现XA接口的数据库的XA模式
- TCC模式:TCC则可以理解为在应用层面的
2PC
,是需要我们编写业务逻辑来实现。 - SAGA模式:为长事务提供有效的解决方案
2、Seata术语
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚,可以集群部署也可单独部署。
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
1.TM 请求 TC 开启一个全局事务。TC 会生成一个 XID 作为该全局事务的编号。XID,会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。
2.RM 请求 TC 将本地事务注册为全局事务的分支事务,通过全局事务的 XID 进行关联。
3.TM 请求 TC 告诉 XID 对应的全局事务是进行提交还是回滚。
4.TC 驱动 RM 们将 XID 对应的自己的本地事务进行提交还是回滚。
3、基于Nacos的Seata搭建
3.1 下载对应jar包和源码
jar地址:https://github.com/seata/seata/releases
源码:https://github.com/seata/seata/tags
3.2 创建数据库
3.3 Seata中配置注册中心
将Seata Server注册到Nacos注册中心
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
注意:请确保client与server的注册处于同一个namespace和group,不然会找不到服务。
3.4 配置Nacos配置中心
3.4.1 在nacos中创建命名空间seata
3.4.2 修改配置Nacos配置中心地址,修改conf/application.yml文件
修改配置
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: seata
group: SEATA_GROUP
username:
password:
data-id: seataServer.properties
3.4.3 上传Nacos配置中心
修改scritp/config-center/config.txt
获取/seata/script/config-center/config.txt,修改为db存储模式,并修改mysql连接配置
store.mode=db
store.lock.mode=db
store.session.mode=db
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
在store.mode=db,由于seata是通过jdbc的executeBatch来批量插入全局锁的,根据MySQL官网的说明,连接参数中的rewriteBatchedStatements为true时,在执行executeBatch,并且操作类型为insert时,jdbc驱动会把对应的SQL优化成 insert into () values (), ()
的形式来提升批量插入的性能。
根据实际的测试,该参数设置为true后,对应的批量插入性能为原来的10倍多,因此在数据源为MySQL时,建议把该参数设置为true。