0%

分布式事务总结

分布式事务总结

要理解分布式事务首先要明白事务是什么,从单机事务的理解迁移到分布式事务,下面从两个角度总结单机和分布式事务

  1. 单机事务 vs 分布式事务
  2. 如何通过并发控制保证单机分布式事务的隔离性

单机/分布式事务

事务作为数据库系统读写操作的高层抽象,代表了数据库的基本操作。一个正常提供服务的数据库系统,其事务必须满足ACID四个性质,其中CI两个性质相互关联,是事务性质研究的重点。

  1. Atomic(原子性):每个事务被看作一个不可分割的单元,要么完全成功要么完全失败,不存在两者的中间状态。数据库系统必须保证任意时刻下事务的原子性
  2. Consistency(一致性):一致性是指数据库满足某种预先定义的约束,任何数据库的操作都必须满足一致性,即从一个满足一致性的状态转移到另一个满足一致性的状态(例如:转账事务要满足转出和转入账户总金额不变)
  3. Isolation(隔离性):一系列并发进程的执行导致数据库的状态改变和按照某种线性顺序执行的状态改变相同(实际上这是serializability的定义)
  4. Durable(持久性):事务一旦提交,其对数据状态的改变不会因为意外事件的发生而丢失

分布式事务可以看作事务+分布式环境,即一个执行范围跨越多个通过网络连接的不同主机的事务,分布式事务既然是事务,同样要满足ACID性质,但是由于分布式环境的复杂性,原有的事务性质保证手段在分布式环境下需要进行调整和新的设计。

ACID实现

Atomic(原子性)和 Durable(持久性)两个性质逻辑上较为相似,即数据库保证事务要么完全不提交,要么完全提交后永不丢失,两条性质通常通过“WAL(Write-ahead-log)” 机制实现

  • WAL(Write-ahead-log):在事务操作真正影响数据之前,首先将操作写入日志中,日志持久化以后才在合适的时机进行修改操作的实际执行,在事务回退(保证A)或者恢复事务结果(保证D)时,通过日志中记录的操作恢复到对应状态
  • 在单机和分布式事务中,均采用WAL机制+复制的方式保证以上性质
    1. MySQL:通过redo、undo log实现了WAL的机制
    2. Amazon Aurora:分布式环境中基于redo log的WAL机制
    3. Spanner:事务中所有的操作执行前,首先写入Paxios日志(基于Paxios的分布式WAL)

Consistency(一致性)和 Isolation(隔离性)在逻辑上具有关联关系,除去静态的一致性保证外(如外键约束),一致性的破坏往往是由于多个事务并发执行未保证“隔离性”,导致的前后状态不一致性,通过保证“隔离性”,可以间接的保证数据库的一致性,“隔离性”的保证涉及到并发事务的控制,即并发控制。

一致性and隔离性

以来自于wikipedia的转账事务为例,阐述当事务并发执行时,由于”隔离性“的控制程度的不同,带来的几个不同程度”不一致性“

  • 数据库存储两个年龄分别为20、25的用户记录
  1. 脏读(dirty read)

    脏读指一个事务能够读到另一个未提交并发执行事务的执行结果,如下图所示。

    • 事务1查询Id=1用户的年龄,同时事务2将用户1年龄修改为21
    • 事务1在事务2提交之前查询到其修改结果21,之后事务2回滚,用户1年龄回滚为20

  2. 不可重复读(Non-repeatable reads)

    不可重复读指一个事务连续两次读取一个对象时,前后状态不一致,即对象值被其他事务修改,如下图所示。

  3. 幻读(Phantom reads)

    幻读与重复读类似,只是不再是某个对象的状态前后不一致,而是数据库表多新数据/少老数据,如下图所示

    • 事务1两次查询年龄区间之间,事务2插入了一个表项

针对以上的并发一致性问题,定义了不同程度的隔离性

  1. 可串行化 Serializable

    最强的隔离级别,保证并发事务按照特定顺序逐个执行,能够避免所有以上的问题,但是实现可串行化性质,会大幅降低数据库性能

  2. 可重复读 Repeatable reads

    可重复读,解决脏读、不可重复读问题的隔离级别,但是会出现幻读

  3. 读已提交 Read committed

    保证事务结果只有在提交以后才能对其他事务可见,能够解决脏读问题

  4. 读未提交 Read uncommitted

    可以读取未提交的事务的执行结果,最低的隔离级别,无法解决脏读问题

并发控制(concurrency control)

上面简单介绍了Isolation的性质特点,数据库要保证上述性质必须通过并发控制实现,并发控制本质上就是对多个访问相同资源的操作/事务等进行协调,并发控制主要有以下三种策略:

  1. optimistic(乐观):允许多个并发操作同时操作数据库,当用户想要修改数据时,由数据库判断是否满足一致性和隔离性要求,若不满足则拒绝执行操作(不阻塞,在发生冲突时撤销操作)
  2. pessimistic(悲观):阻塞所有相同对象的操作(即使不会发生冲突),同一时间一个对象上只有一个事务执行
  3. Semi-optimistic(半乐观):结合上述两种思想
  4. 乐观锁理论上阻塞更少,并发性能更高,实际上由于冲突回滚,在部分情况(写多读少?)性能不如悲观机制。也就是两种机制都有自己适应的场景

主要的手段

  1. 锁(locking):为资源设置锁,通过锁控制并发操作
    • simple locking:每一个事务需要为每一个共享变量在执行读或写之前请求锁,只有在事务完成或者终止时,才释放锁。
    • Two-Phase Locking(两阶段锁):事务可以在执行的过程中不断申请锁,但是一旦释放锁就不能再申请锁
      • Growing Phase:不断地根据数据,申请写锁和读锁,shrinking Phase:不断地释放锁,直到事务结束
  2. Serialization graph checking:检验串行化图中是否存在环
  3. Timestamp ordering:通过时间戳对事务执行顺序排序(分布式系统中常用来保证一致性)
  4. Commitment ordering: 为Commit排序
  5. Multiversion concurrency control] (MVCC) :基于版本快照的并发隔离控制

通过以上并发控制策略,保证了数据库的CI性质,如果我们要将对应问题迁移到分布式环境上问题有何不同?解决方案又有何不同?

来到分布式事务(主要介绍两阶段提交)

从单机到分布式事务,我们首先要找到这个改变带来了哪些新问题?

  1. 计算节点分布于不同的服务器,单个事务的提交涉及到不同服务器的”子事务“的分别提交
  2. 多节点、节点直接通过网络通信等导致系统可能出现更多类型的错误(消息丢失、网络延迟、节点崩溃等等)

既然问题发生了改变,单机并发控制的方法并不能简单的迁移到分布式环境中,提出了新的思路-Two-Phase Commit

  • 引入协调者(Coorrdinator),管理事务涉及到的不同子服务器”子事务“提交,由协调者与所有参与事务服务通信判断是否满足事务提交条件
  • 事务的提交过程如下所示,分为两个阶段
    1. 准备阶段:协调者向所有的参与者发送准备消息,若worker可提交本地”子事务“,返回ok,否则返回not ok。协调者只有在收到所有参与者ok信息后才认为事务可以提交,进入第二阶段。(参与者在此阶段准备如锁等的提交事务的资源)
    2. 提交阶段:协调者向所有参与者发送提交消息,参与者收到消息后,提交事务,返回成功消息。
  • 两阶段提交存在单点失效、同步阻塞等问题

2PC故障恢复问题:

  1. 协调者故障:若协调者故障不会影响正确性,提交的事务不会丢失,未提交的事务不会提交。
  2. 参与者/网络故障:若参与者在准备阶段发送ok之前实现或者ok信息丢失,则协调者需要设置超时机制,超时放弃事务;若参与者在发送ok之后失效,若此时协调者收到了所有ok信息,发送了commit信息,协调者必须等待失效参与者上线、失效参与者也必须能够继续执行提交,否则就会出现部分提交的问题

其他分布式事务实现机制以后有机会再继续进行深入研究

分布式中的一致性

分布式中的一致性与数据库事务中的概念不同,主要考虑的是多副本之间状态的一致性,其实概念上更加接近ACID中的I,按照一致性从强到弱分为以下集中不同的一致性模型

  1. 线性一致性(Linearizability):又被称为Strong consistency or Atomic consistency,所有事务全局有序,使得所有的”读“都能读到最近的”写“,使得分布式系统外部看起来就像一个单机系统。(前提是需要建立一个全局时钟或者顺序确定机制)
  2. 顺序一致性(Sequential consistency):放宽了线性一致性的全局性顺序要求,将一致性的要求分为以下两个方面,放宽了不同机器之间操作的执行顺序先后(zookeeper)
    • 从单机角度看,其读写操作的执行严格按照发出的顺序
    • 从全局角度看,全局只有一个执行顺序
  3. 因果一致性(Causal consistency):对顺序一致性的进一步放宽,只要求保证具有因果关系操作的先后顺序关系(全局认可),其他不具备因果关系的操作的先后顺序在不同节点实际执行顺序可能不同
    • 通过本地执行顺序先后、写后的读等确定因果关系
  4. 最终一致性(Eventually Consistency):从出现网络分区时,分布式系统无法同时保证可用性和一致性,因此定义最终一致性这一概念,在执行某个操作后系统的状态可以是不一致的,但是能够保证的是过一段时间系统的状态最终会达到一致性
    • 由于最终一致性的系统不同部分会出现状态不一致的情况,需要特定机制进行状态同步
    • 在不同副本之间通信交换更新和状态更变,得到一个一致的最终状态

分布式系统中往往通过共识算法+ 并发控制实现一致性的保证

总结

简单的整理了一下目前对于单机事务和分布式事务(单机并发,分布式并行)的理解,分布事务概念本身其实与单机事务相差不大,只是分布式事务的实现机制更加的复杂,仅仅了解了两阶段提交,还有其他许多实现方法等待继续学习

参考

  1. 知乎:分布式系统一致性 - 总结
  2. 知乎:Transaction management:可串行性(serializability)
  3. 知乎:分布式事务综述
  4. wikipedia:Distributed transaction
  5. DDIA第七章-事务