事务
事务:多个命令打包进FIFO队列,然后一次性,顺序执行队列中的命令。
数据库事务 (本地)
ACID
原子性 :一个事务的操作队列
ABC
,要么ABC全部完成
,要么全部不完成
,ABC一个也不做一致性 : 事务中如果出现一个步骤错误,就自动回滚,返回原始
系统状态
。 既,事务前后数据库的状态都是有效的,不会出现错误数据
隔离性 : 多个事务的操作有各自的数据空间,
并行执行
的事务结果和串行的结果一致
。持久性 : 当一个事务执行完毕,执行这个事务所得的结果已经被保存到
持久性介质中
,执行事务的结果不会丢失。
对比 Redis
中的事务 ACID
原子性: Redis 事务是具有原子性的,如果事务操作队列为
ABCD
。ABCD
都是正确的,那么会正确的执行,但是如果AB
是错误的,CD
是可以执行的,那么事务不会回滚
,而且CD会继续执行
。作者解释:事务回滚这种复杂的功能和 redis 设计的高效设计主旨不符,并且认为事务中的错误基本是编程错误产生,所以只会出现在开发环境,所以没有开发回滚功能
一致性: 数据符合数据库本身的定义和要求 ,没有包含非法或者无效的错误数据
3种 Redis 事务可能出错的情况:
入队错误的命令。命令不存在,或者命令格式不正确,比如参数个数。
redis 事务中有入队错误的命令时,不执行事务,所以保持一致性,在2.6.5之前 ,执行其他命令,但不执行入队错误的命令,也是一致的,=执行错误:和原子性中的事务不回滚一样,对数据库键执行了错误类型的操作,会执行之外的数据,也是一致的。
服务器停机:如果没有持久化,数据库GG ,数据一致性
如果持久化,无论是RDB还是AOF 都会根据持久化文件来恢复,不会影响数据库的一致性
隔离性 : Redis
单线程执行事务
,队列中中的命令,自然满足隔离性。持久性: Redis的持久性,和是否做了持久化 开启RDB或AOF相关。以及是否执行了BGSAVE 和 AOF的持久化策略相关,实际就是是否存储到了永久介质。
资源管理器管理本地事务
应用、应用服务器、应用框架,在本地准备会话,开始事务操作,提交回滚,完成会话,将这一系列操作发送给 资源管理器
,资源管理器通过日志
和锁
实现事务的操作。
ACID实现原理
通过 InnoDB日志和锁来保证
1. 隔离性——数据库锁的机制实现,不会产生并发冲突,中间状态隐藏 ,达到串行执行的结果。
2. 持久性—— RedoLog
(重做日志)来实现
RedoLog : 提交之前,将RedoLog 持久化,如果系统崩溃,可以根据RedoLog 将数据恢复早最新的状态
3. 原子性+一致性—— Undo log
Undo log : 将被操作的数据提前备份到一个地方(UndoLog) 失败了/RollBack —> 恢复事务开始之前的状态
分布式事务
分布式事务:事务的参与者、支持事务的服务器、资源服务器、事务管理器 ,位于不同的,
分布式系统的不同节点之上
。 一次大的操作由不同的小的操作组成。小的操作位于不同的服务器上
, 属于不同的应用
,事务需要保证这些小操作事务性。保证不同数据库的事务一致性
。
分布式事务的场景:
比如支付,在线下单,库存和订单状态的数据同步变化(强一致性)
service 产生多个节点:
微服务
resource 产生多个节点:
多节点
分布式事务基础理论 :
CAP 理论
- C一致性 :对于任意一个客户端的读操作,都能返回其他节点上
最新
写操作之后产生的数据,那么就是强一致
,如果读取不到最新
的数据,就是分布式不强一致(弱一致)。 - A可用性 : 非故障的节点在
合理的时间
内返回合理的响应
。 - P分区容错性 :集群中的一台挂了 ,集群不会发生雪崩现象。(选举)
实际情况由于网络延迟和节点宕机的问题,不可能百分百的实现CAP:
1. CP
:放弃 HA
追求一致性和分区容错性 solorcloud zookeeper
,强一致
2. AP
:放弃强一致性 ,追求分区容错性和可用性。比如下面的Base理论方案。
Base 理论
BA:基本可用:分布式系统出现故障的时候,核心功能可用
S:软状态:CAP的C弱一致,系统的中间状态,允许存在中间状态,这里不同于数据允许存在中间状态,可以通过锁的机制实现同步等待
E:最终一致:经过一段时间之后,数据会达到一致。
分布式事务解决方案:
考虑的点: 微服务会带来分布式事务的问题,小团队弄个p的微服务,做个毛的团队设计,分布式事务处理,我们现在这样,负载+docker + 单节点本地的事务 就ok了,通过RPC将各个微服务聚合成一个单机服务。不过度追求设计和增加复杂度。
而分布式事务解决的主要问题就是: 强一致和最终一致的问题 ,下面是3种方案:
2PC
XA:分布式事务协议。 XA Transactions 分为两部分,事务管理器和本地资源管理器 ,主要理解为两个阶段,预备
和 提交执行/回滚
,通过事务管理器
管理这两个阶段。
MySQL对XA事务的支持
需求:5.0.3 + InnoDB存储引擎
XA Mysql 基本过程:
XA {START|BEGIN} xid [JOIN|RESUME] //开启XA事务,如果使用的是XA START而不是XA BEGIN,那么不支持[JOIN|RESUME],xid是一个唯一值,表示事务分支标识符
XA END xid [SUSPEND [FOR MIGRATE]] //结束一个XA事务,不支持[SUSPEND [FOR MIGRATE]]
XA PREPARE xid 准备提交
XA COMMIT xid [ONE PHASE] //提交,如果使用了ONE PHASE,则表示使用一阶段提交。两阶段提交协议中,如果只有一个RM参与,那么可以优化为一阶段提交
XA ROLLBACK xid //回滚
XA RECOVER [CONVERT XID] //列出所有处于PREPARE阶段的XA事务
例子:开启 xatest 的分支事务 ; END ;
启动一个XA事务 ,至于ACTIVE状态 XID 作为事务的标识符
mysql> XA START 'xatest’; //其中'xatest’就是xid的值
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user(name) values("tianshozuhi");
Query OK, 1 row affected (0.00 sec)
至于END状态
mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)
至于Prepared状态
mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.01 sec)
提交和中止事务;
mysql> XA COMMIT 'xatest';
第一阶段: 事务管理器要求 每个涉及到事务的数据库
预提交 precommit 操作给事务管理器,并反映是否可以提交。
第二阶段: 事务协调器要求 每个数据库
提交数据进行事务处理,或者回滚数据
优点:
XA
协议尽量保证了数据的 强一致性
,实现成本较低。MYSQL5.5
开始支持
缺点:
1。单点问题:事务管理器在整个流程中扮演的角色很关键,比如 prepare 完成了,但是 commit 没有完成
,事务管理器宕机,其中的请求资源就会产生阻塞
,导致数据库崩溃无法使用。
2 。同步阻塞:prepare 之后,资源管理器中的资源会阻塞, 直到提交
,释放资源,不能支持 高并发
。
3 。 数据不一致
: 其实XA的核心就是两阶段提交,仍然存在不强一致的可能性,因为在第二个阶段,commit的时候 某些参与的数据库可能因为网络原因没有commit 此操作。
TCC补偿模式:Try-Confirm-Cancel
相比2PC XA,加入了confirm 确认的步骤。适用于强一致的业务。
- 解决了协调者单点,由主业务方发起并完成这个业务活动。业务活动管理器也变成多点,引入集群。解决了
XA的事务管理器单点
问题。 - 同步阻塞:引入超时,超时后进行补偿,并且不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小。
- 数据一致性,有了补偿机制之后,由业务活动管理器控制一致性
TCC3个阶段:
Try-尝试执行:完成所有业务检查(一致性),预留必须业务资源(隔离性)。检查参与业务的所有资源,锁住。
Confirm:确认真正执行业务,不做业务检查,检查Try阶段的业务资源,如果失败则 Cancel ,要求具有幂等性设计,可以失败重试。依靠活动日志。
Cancel:和confirm基本一致。
Rocket MQ分布式事务 消息事务+最终一致性
- 准备消息,会拿到消息的地址
- 执行本地事务
- 通过第一阶段拿到的地址去访问消息,修改状态,消息接受者就能使用这个消息
消息事务——基于消息中间件的两阶段提交,本地事务和发消息放在了一个事务里,事务保证了本地操作成功并且发消息成功,要不都失败
1 A系统向消息中间件发送一条预备消息
2 消息中间件保存预备消息并返回成功
3 A执行本地事务
4 A发送提交消息给消息中间件
1 2 出错 ,事务都会失败,不会执行3 。 3 失败,需要回滚,A需要实现一个消息中间件的回调接口,如果消息中间件 回调发现A事务执行失败,那么回滚预备消息
4 出错,A本地事务成功,