由于目前的场景需要在不同的机器上进行原子操作,同时需要考虑分区和故障的情况,所以就出现了分布式事务这一概念。
本地事务
Transaction management:可串行性(serializability)
事务原语
- begin:声明一个事务的开始
- commit:提交事务,commit成功被执行后,begin~commit之间的逻辑被原子地执行
- abort:取消事务,begin~abort之间的逻辑将被撤销,即产生的影响会消除(比如put修改的值被改回去之类的)。除了人为在逻辑里使用abort,事务本身遇到死锁等情况时也会自动调用abort。
探测死锁:
- 基于超时。
- 以事务作为节点,当事务A等待事务B时,A指向B,形成一张有向图。当图中出现环时,则说明出现死锁。
隔离性
基本概念不再陈述,重点是隔离级别中的可串行化,被称为数据库的黄金标准。乍一听和可线性化有点类似,但其实这是两个领域中截然不同的东西。
可串行化是指,并行的执行一些事物得到的结果,与按照某种串行的顺序来执行这些事务,可以得到相同的结果。实际的执行过程或许会有大量的并行处理,但是这里要求得到的结果与按照某种顺序一次一个事务的串行执行结果是一样的。所以,如果你要检查一个并发事务执行是否是可串行化的,你查看结果,并看看是否可以找到对于同一些事务,存在一次只执行一个事务的顺序,按照这个顺序执行可以生成相同的结果。
所以可串行化的执行顺序和实际的执行顺序有可能是不相同的。而可线性化的顺序是和真实时间匹配的。
并发控制
为了达成可串行化的要求,通常由悲观和乐观两种解决方案。
悲观通过锁来保证串行,而乐观是无锁并发,当要提交时(提交点)检查当前结果是否满足串行化的要求,如果不满足则回滚。
2PL
Transaction management:两阶段锁(two-phase locking)
简单锁(simple locking)或严格锁(strict locking),在事务开始前,需要获取整个事务所需的所有锁,持有这些锁直到提交点进行commit或者abort,然后释放所有锁。(全量获取锁)
2PL的锁更细粒度一点,不需要在事务开始前直接获取所有锁,相反的,在事务运行时动态增量的获取锁,支持某些严格锁**(简单锁)**不允许的并发模式。
在两阶段锁(2PL)中,每个记录都有锁(lock per record),其有两条需要遵循的规则:
- 在开始事务之前,需要lock。(T acquire lock before using)
- 如果一个transaction释放了它所持有的任意一个锁,那它就再也不能获取任何锁。
数据库常用的SS2PL,更加严格的2PL,它要求只能在提交和回滚时释放锁,事务拥有锁之后,只能在commit或abort时释放锁。(T holds until commit or abort),能够有效的避免级联回滚的情况。
2PC
2PC和2PL名字很像,但是2PC是分布式场景下的事务解决方案,全称是两阶段提交协议(2 phase commit),包括准备阶段和提交阶段。在分布式事务处理模型(Distributed Transaction Processing Reference Model,DTP)的定义下,有如下的几个角色:
- AP(Application Program):即应用程序,可以理解为使用DTP分布式事务的程序。
- RM(Resource Manager):即资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务。
- TM(Transaction Manager):事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。
- DTP模型定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现2PC又称为XA方案。
在2PC中RM通常是数据库实例,如果有一个RM在prepare阶段返回no,那么TM就会控制所有RM进行回滚。
崩溃分析
RM在ok后崩溃
由于数据库的WAL技术存在,在操作前会先写redolog和undolog,当机器重启后会回到之前的状态,接收到commit请求,提交本地事务。
TM在ok后,commit前崩溃
这时RM就需要一直等待,不能够擅自提交或回滚事务。
RM在prepare后崩溃
TM会以超时为由回滚所有事务,如果后面RM连接上了,也会因为tid已经过时而放弃提交回滚。
通常会使用共识算法增加TM的可用性,因为TM崩溃后,RM本地的锁也不会释放。
分布式事务:2PC、TCC、sega、TCC、MQ事务消息、本地消息表、AT