1 事务回顾
事务的ACID是通过日志和锁来实现的。
数据库锁
undo log 和 redo log
事务中,每执行一条sql语句对数据造成影响时,就会记录这条语句到redo log中,同时也会记录一条与之相反的操作到undo log。 如:开启事务insert一条记录时,redo log和undo log同时分别记录了这条sql和相反操作的sql。当事务提交时,redo log中的操作将被持久化;当事务回滚时,执行Undo log中的操作,delete掉生成的数据。
原子性和一致性是通过 Undo log(回滚日志)来实现的
持久性是通过 redo log (重做日志) 来实现的
mysql在生成redo log时,会使用innodb log buffer ,先缓冲到内存,再同步到redo log,速度更快。
2 分布式事务概述
定义: 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同分布式系统的不同节点上。
- 服务存在多个节点 (应用层)
- 资源存在多个节点 (db层)
CAP
中文名 | 英文 | 说明 |
---|---|---|
C:强一致性 | Consistency | 一个分布式节点修改了数据,另一个节点能即时读到最新数据。 |
A:高可用性 | Availability | 非故障节点在合理时间返回合理响应。 |
P:分区容错性 | Partition Tolerance | 网络分区故障系统仍能运行。如某台服务器挂掉 |
- cap三者不可全得,只能保证任意两两组合。
- P一般必选,所以常用CP和AP
BASE
Basically Available | 基本可用 | 保证核心功能可用,允许丢失功能 |
---|---|---|
Soft state | 软状态 | 允许存在中间状态,这个状态不影响系统可用 |
Eventually Consitent | 最终一致性 | 经过一定时间后,所有数据最终达到一致 |
3. 解决方案
- 失败,全局回滚
故障分析
一阶段故障
- 协调者:
- 二阶段执行回滚操作失败:不断重试,直到所有参与者都回滚,此时协调者与其他已回滚成功者都处于阻塞状态。
- 二阶段执行commit操作失败: 不断重试,只能铁着头前进,直到提交成功,重试多次无法成功,只好人工介入。
特点
- 尽量保证强一致性
- 同步阻塞
- 效率低
- 极端情况下存在数据不一致风险
3PC 三阶段提交
canCommit, preCommit, doCommitTCC
2pc和3pc都是数据库层面的,而tcc是业务层面的分布式事务
本地消息表
存放本地消息的表,一般放在数据库中,然后在执行业务的时候把业务的执行和将消息放入消息表的操作放在同一个事务中,这样就能保证消息放入本地中业务肯定是执行成功的。全局提交前,协调者去本地消息表查询所有未执行成功的消息,再次重试调用。
需要重试就需要参与者业务幂等,且重试要最大次数,超出后报警人工处理。
本地消息表容忍数据暂时不一致,实现最终一致性。
消息事务(RocketMQ)
半消息:已发送成功到broker但对消费者不可见的消息
先发送半消息,再根据本地事务的结果向broker发送commit或者rollback命令。
如果commit那么订阅就能收到这条消息,然后消费;如果rollback那么订阅方收不到这条消息,等于事务没有执行过。
最大努力通知
本地消息表和MQ事务消息也算是最大努力通知
适用于对时间不敏感的业务,例如短信通知。
4 Seata
AT模式
一阶段:业务数据和回滚日志记录 在同一本地事务中提交,释放本地锁和资源。
二阶段:
- 回滚通过一阶段的回滚日志进行反向补偿
- 此期间对一阶段提交数据上独占写锁
一阶段本地事务提交后,加全局锁,全局锁使用select for update来实现,使用独占写锁直到全局提交或回滚;
通过记录undolog来回滚
TCC
AT依赖关系型数据,tcc则不需要