数据库
首页 > 数据库> > 云原生分布式数据库事务隔离级别(下)

云原生分布式数据库事务隔离级别(下)

作者:互联网

在前文中,我们已经介绍了事务的相关概念以及事务隔离的不同级别,本文将着重介绍快照隔离的发展。

Part 3  快照隔离的发展

论文 A Critique of ANSI SQL Isolation Levels 中提出了快照隔离(Snapshot Isolation)的定义:

这里需要注意:

仔细考虑上述快照隔离的定义,考虑如下几个问题:

  1. CommitTS的获取:如何得到一个比现有的StartTS和CommitTS都大的时间戳,尤其是在分布式系统中;

  2. StartTS的获取:虽然上面提到的StartTS可以是一个很旧的时间,那么StartTS是否需要单调递增;

  3. 提交时进行的冲突检查是为了解决Lost Update异常,那么对于这个异常来说,写写冲突检查是否是充分且必要的;

  4. 分布式、去中心的快照隔离级别该怎样实现。

针对上述问题,下面进行展开。这里将上述提到的快照隔离(SI)记为Basic SI。

分布式快照隔离

本节主要讲解HBase、Percolator以及Omid在快照隔离方面工程实践进展。

HBase

HBase中快照隔离是完全基于多个HBase表来实现的分布式SI:

协议大致实现如下:

HBase采用结构上解耦的方式实现分布式SI,所有的状态都存储到HBase中,每个场景的需求都用不同的表来实现,但这种解耦也带来了性能损失。这里将HBase实现的快照隔离记为HBaseSI。

Percolator

在2010年提出的Percolator在HBase的基础上更加工程化,将涉及到的多个Table合并成了一个,在原有数据的基础上增加了lock、write列:

同时,作为一个分布式的SI方案,仍然需要依赖2PC实现原子性提交;而prewrite和commit过程,则很好地将事务的加锁和2PC的prepare结合到一起,并利用Bigtable的单行事务,来避免了HBaseSI方案中的诸多冲突处理。这里将Percolator实现的快照隔离记为PercolatorSI。

Omid

Omid是Yahoo的作品,同样是基于HBaseSI,但和Percolator的Pessimistic方法相比,Omid是一种Optimistic的方式。其架构相对优雅简洁,工程化做得也不错,近几年接连在ICDE、FAST、PVLDB发表文章。

Percolator的基于Lock的方案虽然简化了事务冲突检查,但是将事务的驱动交给客户端,在客户端故障的情况下,遗留的Lock清理会影响到其他事务的执行,并且维护额外的lock和write列,显然也会增加不小的开销。而Omid这样的Optimistic方案完全由中心节点来决定Commit与否,在事务Recovery方面会更简单;并且,Omid其实更容易适配到不同的分布式存储系统,侵入较小。

ICDE 2014 的文章奠定Omid架构:

TSO维护如下几个状态:

这里的lastCommit即关键所在,表明了事务提交时不再采用和Percolator一样的先加锁再检测冲突的Pessimistic方式,而是:

另外提出了一个客户端缓存Committed的优化方案,减少到TSO的查询;在事务的start请求中,TSO会将截止到start时间点的committed事务返回给客户端,从而客户端能够直接判断一个事务是否已经提交,整体架构如下图所示。

在FAST 2017中,Omid对之前的架构进行了调整,做了一些工程上的优化:

在PLVDB 2018中,Omid再次进行了大幅的工程优化,覆盖了更多的场景:

去中心化快照隔离

上述都是针对分布式SI的实现,它们都有一个共同特征:保留了中心节点,或用于事务协调,或用于时间戳分配。对于大规模或者跨区域的事务系统来说,这仍然存在风险。针对这点,就有了一系列对去中心化快照隔离的探索。

Clock-SI

Clock-SI首先指出,Snapshot Isolation的正确性包含三点:

基于这三个点,Clock-SI提出了如下的算法:

Commit:不论是单partition还是多partition事务,都由单机引擎进行WW冲突检测。

Clock-SI有几点创新:

在工程实现中,还需考虑这几个问题:

论文实验结果很突出,不过正确性论证较为简略,还有待进一步证明。

ConfluxDB

如果说Clock-SI还有什么不足,那可能就是依赖了物理时钟,在时钟漂移的场景下会对事务的延迟和abort rate造成影响。能否不依赖物理时钟,同时又能够实现去中心化呢?

ConfluxDB提出的方案中,仅仅依赖逻辑时钟来捕获事务的先于关系,基于先于关系来检测冲突:

ConfluxDB的这种方案不需要依赖物理时钟,不需要任何wait,甚至不需要单机的事务引擎支持读时间点快照的功能。但是这个方案的不足是,可能Abort rate并不是很好,以及在执行分布式事务时的延迟问题。

Generalized SI

Generalized SI将Snapshot Isolation应用到Replicated Database中,使得事务的Snapshot可以从复制组的从节点读取。这带来的意义有两点,使用一个旧的快照,不会被当前正在运行的事务阻塞,从而降低事务延迟;而从Secondary节点读取数据,则可以实现一定程度上的读写分离,扩展读性能。

Parallel SI

上面的方案中,可以将读请求offload到Secondary节点,一定程度上能够扩展读性能。那么继续将这个思路延伸一下,能不能把事务的提交也交给Secondary节点来执行呢?

这就是Parallel Snapshot Isolation的思路,在跨区域复制的场景下,业务通常会有地理位置局部性的要求,在上海的用户就近把请求发到上海的机房,在广州的用户把请求发到广州的机房;并且在实际的业务场景中,往往可以放松对一致性和隔离性的要求。Parallel放弃了Snapshot Isolation中对Commit Total Order的约束,从而实现了多点的事务提交。在通用数据库中可能很难使用这样的方案,但实际的业务场景中会很有价值。

Serializable SI

Snapshot Isolation所区别于Serializable的是Write Skew异常,为了解决这个异常,可以基于Snapshot Isolation进行优化,并且尽量保留Snapshot Isolation的优秀性质,进而提出了Serializable SI。

论文 Serializable isolation for snapshot databases 是 Alan D. Fekete 和 Michael J. Cahill 在2009年发表的,是早期研究SSI的理论成果。

论文从串行化图理论说起,在Multi-Version的串行图中,增加一种称之为RW依赖的边,即事务T1先写了一个版本,事务T2读了这个版本,则产生RW依赖。当这个图产生环时,则违背了Serializable。

在论文中作者证明,SI产生的环中,两条RW边必然相邻,也就意味着会有一个pivot点,既有出边也有入边。那么只要检测出这个pivot点,选择其中一个事务abort掉,自然就打破了环的结构。算法的核心就在于动态检测出这个结构,因此会在每个事务记录一些状态,为了减少内存使用,使用inConflict和outConflict两个bool值来记录;在事务执行读写操作的过程中,会将与其他事务的读写依赖记录于这两个状态中。

Write SI

Yabandeh在 论文 A critique of snapshot isolation 中提出Write-Snapshot Isolation。作者首先批判Basic SI,因为Basic SI给人造成了一种误导:进行写写冲突检测是必须的。文章开篇即提出,SI中的LostUpdate异常,不一定需要阻止WW冲突;换成RW检测,允许WW冲突,既能够阻止LostUpdate异常,同时能够实现Serializable,一举两得。

为何WW检测不是必须的?简要论证一下,在MVCC中,写冲突的事务写的是不同的版本,为何一定会有冲突?实际上只有两个事务都是RW操作时才有异常,如果其中一个事务只有W操作,并不会出现Lost Update;换言之,未必要检测WW冲突,RW冲突才是根源所在。

基于RW冲突检测的思想,作者提出Write Snapshot Isolation,将之前的Snapshot Isolation命名为Read Snapshot Isolation。如下图中:

如何检测RW冲突:事务读写过程中维护ReadSet,提交时检查自己的ReadSet是否被其他事务修改过。但实际也不会这么简单,因为通常维护ReadSet的开销比WriteSet要大,且这个冲突检查如何做,难道加读锁?所以在原文中,作者只解释了中心化的Write SI如何实现(BadgerDB使用了这个算法,实现了支持事务的KV引擎)。至于去中心化的实现,可从CockroachDB找到一点影子。

不过RW检测会带来很多好处:

综合上述内容,为实现串行化,传统上只能采用基于锁的并发控制,由于性能问题,很难在实际工程中应用。Serializable SI为高性能的实现可串行化,提供了一种新的路径。

以上内容主要参考 Snapshot Isolation综述。


写在最后

在wiki上PostgreSQL对SSI解释有这么一句话:Documentation of Serializable Snapshot Isolation (SSI) in PostgreSQL compared to plain Snapshot Isolation (SI). These correspond to the SERIALIZABLE and REPEATABLE READ transaction isolation levels, respectively, in PostgreSQL beginning with version 9.1。因此,在讨论任何一款数据库产品实现的隔离级别时,必须了解该隔离级别背后实现的算法原理。

参考文献

1. (https://book.douban.com/subject/26851605/)

2. (https://cs.uwaterloo.ca/~ddbook/)

3. (https://cs.uwaterloo.ca/~ddbook/)

4. (https://dl.acm.org/doi/abs/10.1145/568271.223785)

5. (https://zhuanlan.zhihu.com/p/54979396)

6. (https://zhuanlan.zhihu.com/p/37087894)

7. (https://dgraph.io/blog/post/badger-txn/)

8. (https://wiki.postgresql.org/wiki/SSI)

标签:原生,事务,快照,Isolation,数据库,SI,Snapshot,提交,分布式
来源: https://blog.csdn.net/ZNBase/article/details/122432458