黄东旭解析 TiDB 的核心优势
801
2023-04-03
当数据库遇到分布式
概述
NewSQL日渐火热,无论还是开源的TiDB,CockroachDB还是互联网大厂的Spanner,***都号称NewSQL,也就是分布式数据库。NewSQL的典型特征就是,支持SQL,支持事务,高性能,低成本,高可靠,强一致,易扩展,运维友好等。从NewSQL的演进来看,所谓NewSQL,可以简单理解为NoSQL+传统的关系型数据库的结合,NoSQL强调分布式(高可用,可扩展),关系型数据库则强调事务,SQL。正因为二者的叠加,所以需要把两个领域的概念整合在一起,本文主要想把分布式数据库中几个基本概念讲清楚。
一致性
数据库和分布式系统中都有一致性概念,由于很多英文单词对应的中文都是“一致性”,导致容易产生误区。数据库中的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却没有读到最新值。
对于(b),write(y,2)和read(y,2)有先后顺序,也是符合“写后读”,所以是线性一致性。
对于(c), 有几种可能:
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);保证了“写后读”
但是不同进程看到的执行序列不一样,所以不符合顺序一致性。
可串行化
线性一致性VS可串行化
我们要注意到,讨论线性一致性时,我们讨论的粒度是一个操作,操作是否满足先后关系;而讨论隔离级别时,粒度是一个事务,事务是否与某个串行执行的结果相同。所以,这里就比较特殊了,事务中包含了若干读写操作,我们要保证读到最新,是说后开启的事务的读能读到之前的提交;还是事务中的每个读都能读到读开始之前的提交(读提交)。至少从DDIA(Designing Data-Intensive Application)[2]这本书介绍来看,应该是后者,所以它认为基于S2PL协议实现的可串行化,可以做到线性一致性兼得;而SSI由于是快照读,导致读不能读到最新,所以不满足线性一致性的。
数据库要实现“线性一致性”,需要保证事务操作按全局时钟的先后顺序。对于写而言,通过一个统一的地方分配时间戳,显然先后执行的事务分配的时间戳也满足先后关系。这里实际上需要一个统一“全局时间源”,也就是业内常用的TSO(TimeStamp***)方案,TSO能保证所有事务全局有序。对于读而言,读采用加锁当前读,也能保证读到最新,所以结合S2PL可以兼得可串行化+线性一致性,也就是实现Strict Serializable。
External Consistency(外部一致性)
Spanner通过GPS+原子钟保证了所有事务的写有序,实现了类似TSO的功能,但是避免了TSO的单点可用性和性能问题。它提到External Consistency相比linearizability,主要是约束了非相关并发事务的提交顺序与物理时钟要保持一致,因为linearizability并不约束并发执行的操作。论文中没有提到Spanner如何实现Serializable隔离级别,我猜测是类似SSI的实现,那么仍然做不到Strict Serializable。
总结
分布式数据库中的一致性概念有很多,但含义都不太一样,ACID中的一致性主要强调应用逻辑的一致性,需要应用参与保证一致性,CAP中的一致性则主要强调多个副本的一致性,写后读是否能读到最新,这里面就衍生了几种一致性,包括线性一致性,顺序一致性,因果一致性等。数据库有隔离级别的概念,对于可串行化隔离级别也要求顺序,实际上与分布式系统的一致性没有什么关系,它更强调隔离,不强调事务执行的顺序是否与真实执行先后顺序保持一致。因此,数据库可能实现了可串行化隔离级别,但是并不一定实现了线性一致性,比如基于SSI实现的可串行化就是这类系统。
参考文档
[6].《Distributed Computing,Principles, Algorithms, and Systems》
[7].《Designing Data-Intensive Applications》
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。