当数据库遇到分布式

概述

NewSQL日渐火热,不管仍是开源的TiDB,CockroachDB仍是互联网大厂的Spanner,Oceanbase都号称NewSQL,也就是分布式数据库。NewSQL的典型特征就是,支持SQL,支持事务,高性能,低成本,高可靠,强一致,易扩展,运维友好等。从NewSQL的演进来看,所谓NewSQL,能够简单理解为NoSQL+传统的关系型数据库的结合,NoSQL强调分布式(高可用,可扩展),关系型数据库则强调事务,SQL。正由于两者的叠加,因此须要把两个领域的概念整合在一块儿,本文主要想把分布式数据库中几个基本概念讲清楚。html

一致性

数据库和分布式系统中都有一致性概念,因为不少英文单词对应的中文都是“一致性”,致使容易产生误区。数据库中的ACID,C是Consistency,这个C主要强调应用逻辑的一致性,好比应用定义的约束,包括外键等。分布式系统的CAP以及一致性协议,也称为一致性。前者主要强调,读是否能读到最新,以及并发场景下操做执行的时序关系,主要包括线性一致性(linearizability),顺序一致性(sequential consistency),因果一致性(causal consistency)等;后者主要强调“共识”,分布式中的多个节点对某个事情(选主,事务提交)达成一致,常见的共识算法包括paxos协议,raft协议等。算法

线性一致性(linearizability)

简单来讲,线性一致性要求,第一,“写后读”,这里写和读是两个操做,若是写操做在完成以后,读才开始,读要能读到最新的数据,并且保证之后也能读操做也都能读到这个最新的数据。第二,全部操做的时序与真实物理时间一致。相对于“写后读”,第二点要求即便不相关的两个操做,若是执行有前后顺序,线性一致性要求最终执行的结果也须要知足这个前后顺序。好比,操做序列(写A,读A,写B,读B),那么不只,读A,读B能读到最新A值和B值;并且要保证,若是读B读到最新值时,读A必定也能读到最新值,也就是须要保证执行时序与真实时序相同。第三点,若是两个操做是并发的(好比读A没有结束时,写B开始了),那么这个并发时序不肯定,但从最终执行的结果来看,要确保全部线程(进程,节点)看到的执行序列是一致的。数据库

下图对线性一致性有详细的论述,来源于[6]并发

顺序一致性(sequential consistency)运维

相比线性一致性,主要区别在于,对于物理上有前后顺序的操做,是否要保证这个时序。具体而言,对于单个线程,操做的顺序仍然要保留,对于多个线程(进程,节点),执行的事件的前后顺序与物理时钟顺序不保证。可是要求,从执行结果来看,全部线程(进程,节点)看到的执行序列是同样的。详细定义来源于[6]分布式

                             

下图的例子很好的区分了线性一致性和顺序一致性。性能

                             

对于(a),执行序列write(y,2),read(x,0),write(x,4),read(y,2),结果符合要求,可是从客户端的角度来看,write(x,4)先于read(x,0)执行,可是read却没有读到最新值。google

对于(b),write(y,2)和read(y,2)有前后顺序,也是符合“写后读”,因此是线性一致性。spa

对于(c), 有几种可能:.net

1).write(x,4),read(y,0),write(y,2),read(x,0),x的写后读,不符合要求;

2).write(y,2),read(x,0),write(x,4),read(y,0),y的写后读,不符合要求。

因此既不符合线性一致性,也不符合顺序一致性。

因果一致性(causal consistency)

相对于顺序一致性,弱化了不相关操做是否须要保序

对于b),p1和p2 w(x)是没有前后关系的,所以谁先发生都是能够的。

从p3的视角来看,操做执行的序列是w(x,7),r(x,7),w(x,2),r(x,2),w(x,4);保证了“写后读”

从p4的视角来看,操做执行序列是w(x,2),w(x,4),r(x,4),w(x,7),r(x,7);保证了“写后读”

可是不一样进程看到的执行序列不同,因此不符合顺序一致性。

                              

可串行化

上一篇文章讲了数据库中异常和隔离级别,实际上隔离级别是纯粹数据库领域的概念与分布式系统并无交集,好比读未提交,读提交,可重复读以及可串行化。对于数据库而言,咱们说Serializable,是说并发场景下,多个并发事务最终执行的序列与某个串行执行的序列相同(无事务并发,事务的执行没有重叠)。那么如何实现并发控制来达到可串行化调度。数据库中对于同一对象的操做可能存在几类冲突,包括读写冲突,写写冲突,写读冲突等,若是解决了这些冲突,也就实现了可串行化调度。实际上冲突可串行化调度是可串行调度的充分条件,并不是必要条件,详细展开能够看这篇blog,而咱们实际的数据库系统中实现可串行化调度也是解决冲突串行化问题。主要有两种,一种是基于S2PL(Strict 2 Phrase Locking),事务操做过程当中,对读加读锁,对写加写锁,事务提交时,才将锁释放,为了不幻读,还须要实现间歇锁等;另一种,是基于Snapshot的SSI隔离级别,这种实现与S2PL的主要区别在于,读仍然采用快照读,不加锁,读写不互斥,为了实现可串行化调度,须要收集事务的读写操做信息,并判断是否事务有相互依赖的状况(冲突成环),若有,则将冲突的事务回滚,其实是first-commit-win原则,最后致使成环的事务会被回滚。具体能够参考论文:Serializable Isolation for Snapshot Databases,目前商业数据库PG和CockroachDB都是实现了SSI隔离级别。而MySQL的InnoDB存储引擎则是采用了S2PL实现了可串行化隔离级别。

线性一致性VS可串行化

前面分别介绍了分布式系统中的一致性以及数据库中的可串行化隔离级别,分布式数据库显然是分布式系统,也是数据库系统,那么是否能作到线性一致性+可串行化,就是所谓的“Strong Consistency”。这个定义来源于Jepsen的一篇blog,具体能够看下图。

                             

咱们要注意到,讨论线性一致性时,咱们讨论的粒度是一个操做,操做是否知足前后关系;而讨论隔离级别时,粒度是一个事务,事务是否与某个串行执行的结果相同。因此,这里就比较特殊了,事务中包含了若干读写操做,咱们要保证读到最新,是说后开启的事务的读能读到以前的提交;仍是事务中的每一个读都能读到读开始以前的提交(读提交)。至少从DDIA(Designing Data-Intensive Application)[2]这本书介绍来看,应该是后者,因此它认为基于S2PL协议实现的可串行化,能够作到线性一致性兼得;而SSI因为是快照读,致使读不能读到最新,因此不知足线性一致性的。

                       

数据库要实现“线性一致性”,须要保证事务操做按全局时钟的前后顺序。对于写而言,经过一个统一的地方分配时间戳,显然前后执行的事务分配的时间戳也知足前后关系。这里实际上须要一个统一“全局时间源”,也就是业内经常使用的TSO(TimeStampOracle)方案,TSO能保证全部事务全局有序。对于读而言,读采用加锁当前读,也能保证读到最新,因此结合S2PL能够兼得可串行化+线性一致性,也就是实现Strict Serializable。

External Consistency(外部一致性)

google Spanner论文还提到一个外部一致性的概念,

                             

Spanner经过GPS+原子钟保证了全部事务的写有序,实现了相似TSO的功能,可是避免了TSO的单点可用性和性能问题。它提到External Consistency相比linearizability,主要是约束了非相关并发事务的提交顺序与物理时钟要保持一致,由于linearizability并不约束并发执行的操做。论文中没有提到Spanner如何实现Serializable隔离级别,我猜想是相似SSI的实现,那么仍然作不到Strict Serializable。

总结

分布式数据库中的一致性概念有不少,但含义都不太同样,ACID中的一致性主要强调应用逻辑的一致性,须要应用参与保证一致性,CAP中的一致性则主要强调多个副本的一致性,写后读是否能读到最新,这里面就衍生了几种一致性,包括线性一致性,顺序一致性,因果一致性等。数据库有隔离级别的概念,对于可串行化隔离级别也要求顺序,实际上与分布式系统的一致性没有什么关系,它更强调隔离,不强调事务执行的顺序是否与真实执行前后顺序保持一致。所以,数据库可能实现了可串行化隔离级别,可是并不必定实现了线性一致性,好比基于SSI实现的可串行化就是这类系统。

参考文档

[1].spanner论文

[2].https://jepsen.io/consistency

[3].http://www.bailis.org/blog/linearizability-versus-serializability/

[4].Spanner存储层实现

[5].Serializable Isolation for Snapshot Databases

[6].《Distributed Computing,Principles, Algorithms, and Systems》

[7].《Designing Data-Intensive Applications》

相关文章
相关标签/搜索