事务定义及特性
事务是由一系列对数据库中数据进行访问与更新的操作所组成的一个程序执行逻辑序列。这些操作要么全都执行,要么全都不执行,是一个不可分割的工作单元。
比如我们进行银行转账1万元,要进行两个原子动作:动作一:先从客户A账号扣除1万元;动作二:然后在客户B账号上增加1万元。这两个动作一定要一起完成,不管服务器发生停电,断网还是其它故障。
ACID特性
不管是本地事务,还是分布式事务,必须满足事务的四大特性:
- 原子性(Atomicity)原子性确保事务作为一个不可分割的工作单位,要么全部执行,要么全部不执行。
- 一致性(Consistency)一致性保证事务完成后,数据库从一个一致性的状态转变到另一个一致性的状态。
- 隔离性(Isolation)隔离性防止多个事务并发执行时相互干扰。
- 持久性(Durability)持久性确保一旦事务提交,其对数据所做的任何更改都将永久保存。
不同的仅仅是跨数据库,跨服务的两个或多个操作。
事务隔离级别
我们在使用关系数据库的时候,需要我们权衡业务并发量,业务数据隔离诉求两个核心要素,来决定多个事务之间采用什么样的隔离级别。
读未提交(READ UNCOMMITTED):
- 允许事务读取未被其他事务提交的修改。
- 可能导致脏读(Dirty Read):一个事务读取到另一个事务未提交的数据,若该未提交事务回滚,则读取到的数据是无效的。
- 隔离性最差,并发性高,但数据一致性难以保证。
读已提交(READ COMMITTED):
- 允许事务读取已被其他事务提交的修改。
- 解决了脏读问题,但可能出现不可重复读(Nonrepeatable Read):在同一个事务内,多次读取同一数据集合时,由于其他事务的提交,导致每次读取结果可能不同。
- 适用于大多数应用场景,能够较好地平衡数据一致性和并发性。阿里DB默认采用这种隔离级别。
可重复读(REPEATABLE READ):
- 确保在同一事务内,多次读取同一数据的结果是一致的。
- 解决了脏读和不可重复读问题,但可能出现幻读(Phantom Read):一个事务读取到另一个事务新增的数据。
- MySQL的默认事务隔离级别。通过多版本并发控制(MVCC)等技术实现,但可能引入锁机制以解决幻读问题。
串行化(SERIALIZABLE):
- 强制事务串行执行,以避免脏读、不可重复读和幻读问题。
- 隔离性最高,但并发性能最差,因为事务必须按顺序执行。
- 适用于对数据一致性要求极高,但对并发性要求不高的场景。
分布式事务CAP理论
CAP原则
CAP原则是由加州大学伯克利分校的Eric Brewer在2000年提出的,旨在解决分布式系统中数据一致性和系统可用性之间的权衡问题。
- 一致性(Consistency),在分布式系统中的所有数据备份,在同一时刻是否同样的值。即当更新数据操作成功并返回客户端后,所有的节点在同一时间的数据保持完全一致。这是对数据准确性的严格要求。
- 可用性(Availability),保证每个请求不管成功或者失败都有响应。即系统必须能够很好地为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
- 分区容错性(Partition tolerance),系统中任意信息的丢失或失败不会影响系统的继续运作,或任意节点的丢失都不影响其他节点的继续运行。
例子:
CP : hbase、redis、ZooKeeper、交易系统
AP: memcached、facebook、商品详情页
BASE理论
BASE理论:在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)之间存在权衡。CAP原则指出一个分布式系统不可能同时满足一致性、可用性和分区容错性。而BASE理论则是在CAP理论的基础上发展而来,它强调在非强一致性的情况下,如何通过牺牲部分可用性来达到最终的一致性。
XA分布式事务
XA分布式框架有Atomikos、JOTM、ShardingSphere等。另外Spring框架也提供了对分布式事务的支持,包括XA事务。
原理
XA分布式事务通过两阶段提交协议来保证事务的ACID特性:
预备阶段(Prepare Phase):
- 全局事务管理器要求每个参与者将本地事务准备好,但是并不执行真正的提交。
- 参与者收到指令后执行本地事务操作,但保持事务为准备状态(不提交),并返回准备结果给全局事务管理器。
提交阶段(Commit Phase):
- 如果所有参与者都准备好了,全局事务管理器要求每个参与者执行真正的提交操作。
- 如果任何一个参与者出现问题(如准备失败或通信超时),则全局事务管理器要求所有参与者回滚事务。
优点
- 应用侵入小:不需要在业务中做额外的逻辑处理,对用户无感知。开发简单。
- 数据强一致性:基于两阶段提交协议,提供了数据强一致性的保障。
- 可扩展性:基于资源管理器的事务管理机制,可以方便地扩展到多个数据库或资源管理器上。
缺点
- 同步阻塞:分两阶段提交,对全局事务资源锁的释放取决于所有资源管理器处理事务的总耗时,并发情况下效率较低,互联网大流量场景一般不会采用这种事务机制。
- 单点故障:事务管理器故障会导致整个服务不可用。
- 故障情况下导致的数据不一致:提交阶段不允许出错,如若出现网络故障或资源管理器宕机,可能导致数据最终不一致。
TCC
TCC框架有阿里开源的Seata、华为的TCC-Transaction等。
原理
TCC(Try-Confirm-Cancel)核心思想是将复杂的分布式事务分解为三个阶段来实现事务的一致性。特点:分布提交、乐观锁、冥等性、一致性。
1. 尝试(Try)阶段
- 在此阶段,事务的参与者会尝试执行事务的业务逻辑,并预留必要的资源。这包括执行一些前置操作,如检查资源是否可用、锁定资源等,但不真正提交事务。预留资源是为了确保在后续阶段能够成功执行事务。
- 如果所有参与者的Try操作都成功,则事务进入下一阶段;如果有任何参与者失败,则事务进入取消(Cancel)阶段。
2. 确认(Confirm)阶段
- 在此阶段,如果Try阶段成功,参与者会根据之前预留的资源来执行真正的业务操作,并提交事务。这包括更新数据库、发送消息等操作,以确保事务的原子性和一致性。
- 如果所有参与者的Confirm操作都成功,则事务提交完成;如果有任何参与者失败,则事务进入取消(Cancel)阶段,以回滚之前的操作。
3. 取消(Cancel)阶段
- 在此阶段,如果Try或Confirm阶段中有任何参与者失败,所有参与者都会执行取消操作,释放之前预留的资源,并回滚之前的操作。确保发生错误时能恢复到原始状态。
优点
灵活性:允许应用自己定义数据库操作的粒度。
性能优化:通过业务层面的事务定义,避免了长事务的问题,提高了性能。
强隔离性:适用于需要强隔离性、严格一致性要求的业务活动。
缺点
开发成本:TCC要求业务逻辑的每个分支都需要实现Try、Confirm、Cancel三个操作,增加了开发成本。
实现难度:需要根据不同的失败原因实现不同的回滚策略,增加了实现的复杂性。
幂等性要求:Confirm和Cancel接口必须实现幂等性,以确保在网络超时或异常情况下,重复调用不会导致不一致的问题。
消息分布式事务
消息分布式事务是eBay在2008年公开的,核心原理通过将需要分布式处理的本地事务通过消息日志的方式记录下来,并异步执行这些本地事务。多个本地事务通过错误消息重发,消息日志对账等手段来确保多个事务最终一致性。
由于互联网应用中并发量大,对可用性要求较高,侧重与AP,因此这种方案思想在大厂中被采用较多,像阿里的交易、广告等子系统应用比较多。
应用层简单实现
1、服务1事务 发起本地变更事务操作1,并记录事务凭证,发消息。
2、服务2事务 收消息,执行本地变更事务操作2,并发送ACK回执。
3、服务1收到ACK,删除事务凭证消息。
4、加上定时任务检查未删除的事务凭证,重试/回滚,以达到最终一致性。相当于优先选择AP。
MetaQ事务消息
用消息系统来实现二阶段提交。
- 发送方向 MQ 服务端发送消息。
- MQ Server 将消息持久化成功之后,向发送方 ACK 确认消息已经发送成功,此时消息为半消息。
- 发送方开始执行本地事务逻辑。
- 发送方根据本地事务执行结果向 MQ Server 提交二次确认(Commit 或是 Rollback)
- MQ Server 收到 Commit 状态则将半消息标记为可投递,订阅方最终将收到该消息
- MQ Server 收到 Rollback 状态则删除半消息,订阅方将不会接受该消息。
- 在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达 MQ Server,经过固定时间后 MQ Server 将对该消息发起消息回查。
- 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
- 发送方根据检查得到的本地事务的最终状态再次提交二次确认,MQ Server 仍按照步骤 4 对半消息进行操作。