原作者:Andrew Pavlo(卡内基梅隆大学)Matthew Aslett(451研究所)
摘要
近年来出现了一种称为NewSQL的新型数据库管理系统(DBMS),它们号称有能力扩展现代在线交易处理(on-line transaction processing, OLTP)系统的工作负载,这对于以前的系统来说是无法做到的。NewSQL这个词是本文的作者之一在2011年的一篇讨论对传统巨头(Oracle,IBM,Microsoft)地位发起挑战的新型数据库系统的商业分析报告中提出来的。另一作者则曾经担任第一代NewSQL DBMS的系统的开发者。从2011年后,一些商业公司和研究项目开始使用NewSQL来描述他们的系统。
鉴于传统的DBMS已经发展了近40年,有必要仔细推敲一下NewSQL的优势是真如他们所说,还是仅仅是一种商业宣传行为。如果真的可以获得更好的性能,那么下一个问题自然就是它们是真的有技术突破,还是仅仅因为硬件方面的发展使得原来的问题已不再是瓶颈?
为了探讨这些问题,我们先讨论了数据库的发展历史,以此理解NewSQL出现的背景和原因。然后从一些细节方面深入讨论了NewSQL的概念,特点,分类,以及在各个分类下面的NewSQL系统。
- 数据库管理系统(DBMSS)的简要发展历史
第一代DBMS出现在1960年代中期。IBM开发的IMS用于记录土星V和阿波罗空间探索项目中的供应链和仓储信息。它第一个提出将应用代码和数据操作进行分隔的思想,使开发者只需要关注数据的产生和访问,无需考虑操作和访问这些数据的复杂性。1970年代,IBM和加州大学借鉴IMS的思想分别构建了System R和INGRES,成为第一代关系型的DBMS。其中INGRES很快被其他的大学用于信息系统,接着在1970年代后期进行了商业化。在同一时期,Oracle发布了第一版与System R的设计非常类似的DBMS。其他公司在1980年代早期也纷纷通过推出自己的DBMS系统获得了成功,包括Sybase和Informix。尽管IBM从未将System R开放给公众,但在它的基础代码上于1983年推出了一个新商用的关系型数据库系统——DB2。
为了克服关系模型和面向对象编程语言之间的失配问题,1980年代后期和1990年代早期左右出现了一种新型的DBMS。因为不具备像SQL语言那样的统一的标准接口,所以这种面向对象的DBMS并没有被市场大规模接受。不过,当主要的厂商在十年后添加了对象和XML支持,二十年后添加了面相文档的NoSQL系统之后,这类系统的许多设计思想最终被并入了关系型DBMS中。
在1990年代,另一个值得关注的事件是当今两大主要开源DBMS的诞生。1995年,MySQL起源于瑞典,它建立在ISAM的mSQL系统之上。PostreSQL则是在1994年由两个伯克利大学的研究生在QUEL的Postgres的代码上添加了SQL支持而诞生。
到了2000年代,由于互联网应用的兴起,对系统资源的需求受到了前所未有的挑战。互联网应用需要支持大规模的并发用户,并且要保持永远在线。但是这些新应用的数据库却因为无法支持如此大规模的数据和访问量而成为了整个系统的瓶颈。最简单直接的办法是不断升级DBMS的硬件系统,使用更多的CPU,内存和硬盘。但是这种方法只是提高了性能,并且呈现明显的收益递减效应。更糟糕的是,将数据库从一个机器迁移到另一个机器是一个比较复杂的过程,通常需要较长的停机时间。而这对于Web应用来说是不可接受的。为了解决这个问题,一些公司推出了数据库中间件,对原有的单节点数据库进行数据分片,并存放到由廉价机器组成的分布式的集群里。对于应用程序来说,数据库中间件是一个逻辑上的单节点数据库,但实际上它的存储横跨了多台物理机器。当应用向数据库发起操作时,数据库中间件会自动将操作指令发送到集群中的一个或多个节点来执行。节点执行之后将结果发送回中间件,再由中间件反馈给应用。比较著名的数据库中间件包括eBay的Oracle的集群和Google的MySQL集群。这种方法后来也被Facebook采用,建立了自己的MySQL集群并应用至今。
数据分片中间件在简单操作(如读取或更新单条记录)时能工作得很好,但对于在一个事务中更新多条记录或者JOIN表之类的复杂操作时就无能为力。例如eBay中间件要求开发者在其应用的代码里实现所有的JOIN操作。
于是一些公司不再使用数据库中间件,转而开发自己的分布式DBMS。原因有三个方面:1)传统的DBMS将重点放在一致性和正确性上,牺牲了可用性和性能。但是这种设计上的妥协不能满足Web应用大并发量和时时在线的需求。2)很多人认为使用一个完整功能的DBMS(如MySQL)的开销过大,3)同样地,使用SQL来执行简单的查询也被看做是一种过渡使用。
这些问题引发了2000年代NoSQL运动的诞生。NoSQL系统的关键是它们放弃了传统的DBMS强事务保证和关系模型,通过所谓最终一致性和非关系数据模型(例如键值对,图形,文档)来提高Web应用所注重的高可用性和可扩展性。其中最著名的系统是Google BigTable和Amazon的Dynamo。这两个系统最初并不对外开放(虽然现在都已经变成了云服务),所以其他的用户也创建了自己的开源克隆系统。包括Facebook的Cassandra(基于BigTable和Dynamo),PowerSet的Hbase(基于BigTable)。其他初创公司并没有使用Google或者Amazon系统的副本,但仍遵循了NoSQL的哲学,最著名的是MongoDB。
2000年代后期,出现了更具扩展性并且更廉价的分布式DBMS。使用NoSQL的好处(或者说人们想象中的好处)是开发者可以将精力集中在应用,业务或者组织方面,而不用担心DBMS的扩展性。但是,仍有许多应用不能使用NoSQL。因为它们无法放弃强事务和一致性的需求。通常这些都是需要处理复杂关联性数据的企业级应用(例如财务、订单系统,人力资源系统等)。包括Google在内的一些公司发现采用NoSQL DBMS会迫使程序员在应用开发过程中花费过多的精力来处理一致性数据以提高事务的执行效率。于是唯一的解决之道是:要么购买更强大的单节点机器来垂直扩展DBMS,要么开发自己的数据分片中间件来支持事务。无论哪种方法都非常昂贵,并不是所有人都能接受。在这种环境下NewSQL系统出现了。
- NewSQL的兴起
本文关于NewSQL的定义是:这是一类现代关系型的DBMS,旨在为NoSQL的OLTP读写负载提供相同的可扩展性能,同时仍然提供事务的ACID保证。换句话说,这些系统希望达到NoSQL DBMS相同的可扩展性,又能保留从1970年代开始的关系模型和事务支持,使得应用可以执行大规模的并发事务,并使用SQL而不是特定的API来修改数据库的状态。如果应用使用了NewSQL DBMS,开发者不再需要像使用NoSQL一样在应用逻辑里处理最终一致性的问题。我们下面的讨论中,NewSQL的这个解释涵盖了许多学术系统和商业系统。
在2000年代中期出现了数据仓库DBMS,有人认为它们达到了这个标准。例如Vertica,Greenplum,Aster Data)。这些DBMS服务的对象是OLAP系统,并不能认为是NewSQL系统。OLAP DBMS重点是执行复杂的只读查询(例如聚合查询,多维度JOIN等),这些查询需要大量的计算,较长的执行时间,使用超大的数据集,并且每一个查询都是独一无二的。而NewSQL DBMS服务的系统则需要执行读写事务,并具备以下几个特征:1)短生存时间,即没有用户停顿;2)使用索引查询小数据集,不进行全表扫描或者大规模分布式JOIN;3)可重复执行,即不同的输入执行相同的查询。其他人提出了一个更窄的定义,其中NewSQL系统的实现必须使用:1)无锁并发控制方案;2)无共享分布式架构。第三节里列举所有的NewSQL DBMS都具备这个特征,因此我们也认同这个定义。
- NewSQL的分类
基于上述的定义,我们可以来看看现在有哪些NewSQL DBMS。为了简化分析,我们将研究对象按照实现方式进行分组。我们分出了三个类:1)使用全新的架构;2)重新实现由Google和其他人在2000年代开发的数据分片基础架构,并在此基础上开发的数据库中间件;3)来自云服务提供商的database-as-a-service(DBaaS),同样基于全新的架构。
本文的两位作者都曾在NewSQL系统分类中考虑了替换现有单节点DBMS存储引擎的方案。最常见的例子是对MySQL默认InnoDB存储引擎的替换(例如,TokuDB,ScaleDB,Akiban,deepSQL)。使用新存储引擎的好处是用户可以获得更好的性能而无需修改应用,并且仍能够继续使用DBMS的周边工具和API。其中最有意思的是ScaleDB,它提供了透明的数据分片方案而不使用中间件,通过在不同的存储引擎之间重新分配执行。不过现在这个公司已经转向了其他问题领域。
除了MySQL,还有其他类似的扩展。Microsoft的内存Hekaton OLTP引擎用于SQL Server时几乎可以与传统的磁盘驻留表无缝集成。其他人使用Postgres的外部数据包装器和API钩子来实现相同类型的集成,但目标却是OLAP工作负载(例如Vitesse,CitusDB)。
现在我们认为这种单节点DBMS的存储引擎和扩展并不代表NewSQL系统,因此在我们的分类中将会省略掉它们。MySQL的InnoDB在可靠性和性能方面获得了长足的进步,因此为OLTP应用切换到其他的存储引擎变得没有十分的必要。我们承认从面向行的InnoDB引擎切换到列存储的引擎对于OLAP负载来说是有意义的(例如Infobright,InfiniDB),但一般来说,为OLTP负载替换MysQL的存储引擎业务是失败的数据库项目的墓地。
3.1 新型架构
这个分类包括了NewSQL系统最有趣的部分,因为它们是全新架构的,从头设计的DBMS。也就是说,跟扩展现有系统不同(如Microsoft的Hekaton for SQL Server),它们从一个全新的起点开始设计,摆脱了原有系统的设计束缚。这个分类中所有的DBMS都采用了分布式架构,对无共享资源进行操作,并且包含支持多节点并发控制,基于复制的容错,流控制和分布式查询处理等组件。使用一个全新的为分布式执行而设计的DBMS的好处是,系统所有的部分都可以针对多节点环境进行优化,包括查询优化,节点间通信协议优化等。例如,大部分的NewSQL DBMS都可以在节点之间直接发送内部查询数据,而不用像一些中间件系统一样需要通过中心节点进行转发。
在这个分类中的所有DBMS(Google的Spanner除外)都管理自己的主存储,有的是在内存中,有的是在磁盘中。也就是说,DBMS负责使用定制开发的引擎在其资源上分布其数据库,而不是依赖现成的分布式文件系统(例如HDFS)或存储结构(例如Apache Ignite)。这是很重要的一个特征,因为这使得DBMS能够“向数据发送查询”,而不是“将数据带给查询”,这意味着更少的网络流量。因为跟传输数据(不仅仅是元组,还包括索引,物化视图等)相比,传输查询所需的网络流量要少得多。
对主存储的管理还使DBMS可以使用比HDFS中使用的基于块的复制方案更为复杂灵活的复制方案,因此这种DBMS比那些建立在其他已有技术分层上的系统拥有更好的性能。在现有技术分层上建立的系统有所谓的“SQL on Hadoop”系统(如Trafodion),以及在Hbase上提供事务支持的Splice Machine等等,但我们认为这类系统并不是NewSQL。
但是新架构DBMS的使用情况是呈下降态势的。最重要的原因是许多用户担心这项技术太新,没有大规模的安装基础和实际的生产环境的验证。另外就是社群和有经验的用户数量比流行的DBMS要小许多,许多用户有可能无法使用现有的管理和报表生成工具。一些DBMS,例如Clustrix和MemSQL,通过兼容MySQL的网络协议避免了这类问题。
本类案例:Clustrix, Cockroach, Google Spanner, H-Store, HyPer, MemSQL, NuoDB, SAP HANA, VoltDB.
3.2 透明的数据分片中间件
现在有一些产品跟2000年代的eBay,Google和Facebook一样提供数据分片的中间件。用户可以借助它们将数据库分成多个部分,并存储到由多个单节点机器组成的集群中。数据分片比1990年代出现的数据库联合技术更难,因为每一个节点都要运行相同的DBMS,只维护整个数据库的一部分数据,且不能被不同的应用独立访问或修改。
集中化的中间件组件负责分配查询,协调事务,同时也管理数据的位置,复制和跨节点的数据分区。集群典型的架构是在每个节点上都安装一个中介层来与中间件通信。这个组件负责代替中间件在DBMS实例上执行查询并返回结果,最终由中间件整合。对应用来说中间件就是一个逻辑上的数据库,应用和底层的DBMS都不需要修改。
使用数据分片中间件的核心优势在于,它们通常能够非常简单地替换已经使用了单节点DBMS的应用的数据库,并且开发者无需对应用做任何修改。最常见的中间件目标系统是MySQL,这意味着为了保持与MySQL的一致性,中间件必须支持MySQL的网络协议。Oracle提供了MySQL Proxy和Fabric工具来做这些工作,但是其他公司也开发了自己的协议处理器来避免GPL授权问题。
尽管中间件使用户扩展数据库变得更容易,但它们仍需要在每个节点上安装传统的DBMS(例如MySQL,Post供热SQL,Oracle)。这些DBMS采用的是1970年代提出的面向磁盘存储架构,不能像新架构的NewSQL系统那样使用面向内存的存储管理和并发控制方案。以前的研究表明,面向磁盘的架构阻碍了传统的DBMS通过提升CPU核数和内存容量进行向上扩展。中间件方法会导致在分片节点上执行复杂查询操作的时候出现冗余的查询计划和优化操作(即在中间件执行一次,在单节点上再执行一次),不过所有节点可以对每个查询使用局部的优化方法和策略。
本类案例:AgilData Scalable Cluster, MariaDB MaxScale, ScaleArc, ScaleBase.
3.3 Database-as-a-Service
最后一个分类是云服务提供商的NewSQL方案,database-as-a-service,也称为DBaaS。通过这些云服务,用户不需要在自己的硬件设备上或者云端虚拟机上安装和维护DBMS。DBaaS的提供商负责维护所有的数据库物理机及其配置,包括系统优化(例如缓冲池调整),复制,以及备份。交付给用户的只是一个连接DBMS的URL,以及一个用于监控的仪表盘页面或者一组用于系统控制的API。
DBaaS的客户根据他们预计使用的系统资源来付费。因为不同的数据库查询在计算资源的利用上差距非常大,DBaaS提供商通常不会采用块存储服务(例如Amazon的S3,Google的Cloud Storage)常用的依据调用次数计费,而更倾向于采用预付费的订阅方式。即客户指定所需的最大的存储空间,CPU数量,内存空间等,服务提供商则会在服务期间保证这些资源的可用性。
因为从规模经济角度来看,DBaaS的主要提供商也是云计算服务的主要提供商,但几乎所有的DBaaS仅仅提供一个传统的单节点DBMS实例(例如MySQL)。Google Cloud SQL, Microsoft的Azure SQL, Rackspace Cloud Database, 以及Scaleforce Heroku都是这么做的。因为它们同样使用了从1970年代就沿用至今的面向磁盘的存储架构,我们不把这种单实例的系统算作NewSQL。一些提供商(例如Microsoft)对DBMS进行了一些改造,提供了对多租户的支持。
我们仅仅认为那些基于新型架构的DBaaS是NewSQL。最著名的例子是Amazon的Aurora for MySQL RDS,它与InnoDB的最大区别在于它使用日志结构化存储管理器来提高I / O并行性。
另外一些公司的产品并没有自己的数据中心,他们的DBaaS软件建立在公有云平台之上,例如ClearDB能够让客户将其部署在任何的主流云平台上。这么做的好处是用户可以把数据库建立在同一个地区不同的云平台上,以避免由于云服务中断而导致的停机。
Aurora和ClearDB是2016年这个分类下仅存的两个产品。我们注意到其他公司在这个领域的产品都失败了(例如GenieDB,Xeround),原有的客户不得不在他们关闭云服务前迁出他们的DBaaS并寻找下一个提供商。我们将他们的失败总结为超出市场需求,价格上与主要竞争对手没有拉开差距。
分类案例:Amazon Aurora,ClearDB
- NewSQL的现状
接下来我们将讨论NewSQL DBMS的特点,以理解这些系统的创新之处。文末所附的列表是我们分析工作的总结。
4.1 主内存存储
自从1970年代以来,所有主流DMBS都采用了面向磁盘的存储架构设计。在这些系统中,数据库的主要的存储位置被假定为在一个可进行块寻址的永久性存储设备上,例如SSD,HDD。因为在这些设备上进行读写操作非常慢,DBMS使用内存来缓存从磁盘读取的块,并缓冲来自事务的更新。这是非常必要的,因为当时的内存非常昂贵,而且容量与磁盘相比非常有限。而现在内存的容量和价格都到达了可以将大部分的数据库都容纳进去的程度。使用内存作为主存储的好处是它支持针对性的优化,因为DBMS不必假设事务需要在任何时间随机地访问不在内存中的数据,许多需要处理诸如缓冲池或者重量级并发控制的组件不再是必须的,所以系统将获得更好的性能。
有一些NewSQL DBMS是基于主内存架构的,包括研究性的系统(例如H-Store, Hyper)和商业系统(例如MemSQL,SAP HANA,VoltDB)。这些面向主内存的系统的性能比面向磁盘的处理OLTP的DBMS要高很多。
将数据库全部放在主内存的思想并不是最新的。1980年代初,威斯康辛-麦迪逊大学的开创性研究为内存数据库DBMS的许多方面奠定了基础,包括索引,查询处理和恢复算法等。同时期第一个分布式主内存DBMS——PRISMA/DB被开发出来。第一个商用的主内存DBMS——Altibase则出现在1990年代。Oracle的TimesTen和AT&T的DataBlitz是这种方法的早期实现。
主内存NewSQL系统一个比较新的点是它有能力将数据库的部分子数据集驱逐到持久存储以减少内存的占用。这种类型的DBMS可以把容量比内存更大的数据库放到内存里,而无需切换回面向磁盘的存储架构。一般的方法是使用一个内部的跟踪机制,一旦发现那些不再被访问的数据元组,就立即将其驱逐出内存。H-Store的anti-caching组件可以将这些不被访问的数据元组存放到面向磁盘的存储器中,同时在数据库中添加一条“墓碑”信息来记录这些数据的位置。当事务试图通过“墓碑”记录访问元组时,它会被终止,然后另一个独立线程会将数据异步地放回到内存中。另一种支持“大于内存数据库”的变体是EPFL的一个学术项目,它在VoltDB中使用OS虚拟内存分页技术。为了避免假阴性,所有的DBMS在数据库的索引中保留了已驱逐元组的键,这使那些具有许多次级索引的应用在内存节省方面的效果变差。虽然不是NewSQL DBMS,Microsoft的Project Sibera for Heikaton的每个索引都保持了一个Bloom过滤器,以减少内存中用于跟踪已驱逐元组的内存开销。
MemSQL采用了完全不同的方法来实现“大于内存数据库”的功能。系统管理员可以手动设定DBMS将某个表存储为列格式。MemSQL并不为磁盘存储的元组在内存中保存任何跟踪元数据。它将这些数据组织在日志结构化存储中以减少更新的开销,这在传统的OLAP数据仓库通常很慢。
4.2 分区/分片
几乎所有的分布式NewSQL DBMS水平扩展方案都是将数据库分割成不相交的数据集,这称之为分区或者分片。
在分区的数据库上进行分布式事务处理并不是一个新的想法。这些系统的许多基本原理来自伟大的Phil Bernstein(和其他人)在1970年代后期的SDD-1项目中的开创性工作。1980年代的早期,两个开创性的单节点DBMS项目,Syste R和INGRES的小组同时创建了分布式版本。IBM的R系统是一个类似于SDD-1的,无共享的,面向磁盘的分布式DBMS。INGRES的分布式版本给人们留下最深刻印象的是它的动态查询优化算法,递归地将分布式查询分解成更小的部分。之后,威斯康辛-麦迪逊大学的GAMMA项目探索了不同的分区策略。
但是这些早期的分布式DBMS并没有真正获得成功,原因有两个。首先是当时硬件成本太高,大部分的客户不可能购买足够多的设备来构建数据库集群环境。其次是应用对分布式DBMS的高性能需求还没有成熟,当时对DBMS吞吐量的最高要求也只有每秒数千笔交易。而我们现在这两点原因都不复存在。构建大规模的数据密集型应用从未如此简单,部分原因是开源分布式系统工具,云计算平台和廉价的移动设备的激增。
数据库的表被水平划分为多个片段,划分的边界基于一个或多个列的值。这些列被称为分区属性。基于这些属性值,DBMS使用范围或散列的分区将每个元组分配给某一个片段。 来自多个表的相关片段被组合在一起以形成由单个节点管理的分区。 该节点负责执行所有访问存储在其分区中的数据的查询。 只有DBaaS系统(Amazon Aurora,ClearDB)不支持此类型的分区。
理想情况下,DBMS应该能够在多个分区上分布式地执行查询,然后将所有结果合并为一个单一的结果返回给调用方。除了支持本地分区的ScaleArc之外的所有NewSQL系统都提供此功能。
分区是许多OLTP应用数据库都具备一个重要特性。这些数据库schema可以转换为树状结构,树的后代与根具有外键关系。然后依据这些关系关联的属性对表进行分区,使得单个实体的所有数据都能位于同一分区。举例来说,一个树的根节点可能是一个客户表,数据库将会根据每一个客户进行分区,将每个人的订单记录和账户信息存放在一起。这么做的好处是它使大部分的事务只需要访问一个单独的数据分区就够了。因为不需要使用原子通信协议(例如2阶段提交)来保证事务在不同节点上正确执行,又进一步减少了网络通信开销。
NewSQL DBMS中,NuoDB和MemSQL采用了与同质集群节点架构采用不同方案。NuoDB指定一个或多个节点作为每个数据库分区的存储管理器(简称为SM)。SM将数据库分成块(在NuoDB的术语中称之为原子)。集群中所有其他的节点被当做事务引擎(简称为TE),它是原子在内存中的缓存。当处理一个查询时,TE通过SM或其他TE可获得这个事务所涉及的所有原子。获得一个写入锁之后,对原子进行的任何更改都将广播给其他的TE和SM。为了避免原子在节点之间来回移动,NuoDB公开了负载均衡方案以确保使用的数据会驻留在同一个TE中。这意味着NuoDB最终会具备与其他分布式DBMS相同的分区,但它不必进行数据库的预分区或对表关系进行预定义。
MemSQL同样使用了一个类似的异构架构,包括只具备执行功能的聚合器节点和存储实际数据的叶节点。MemSQL与NuoDB最大的不同在于二者如何减少从存储节点拉到执行节点的数据量。在NuoDB中,TE会缓存原子来减少从SM中读取的数据量,而MemSQL的聚合节点不缓存任何数据,但叶子节点会执行部分查询,以此减少发送到聚合节点的数据量。这在NuoDB中是不可能的,因为存储管理器只有数据存储功能,没有执行查询的能力。
这两个系统都能够向DBMS集群中添加执行资源(NuoDB的TE,MemSQL的聚合节点)而无需对数据库进行重新分区。SAP HANA的一个研究性的原型系统同样采用了这个方法。不过,从性能和操作复杂度方面,异构架构是否比同构架构(即所有的节点都可以同时执行查询和存储数据)更优秀仍有待进一步通过实践来检验。
NewSQL分区的一个新的功能是部分系统支持实时迁移。它们允许DBMS将数据在物理资源间进行迁移,以达到系统重新平衡,缓解热点压力,动态增加/减少DBMS容量的目的。这一点跟NoSQL系统的重新平衡类似,但是难点在于NewSQL DBMS需要在迁移中仍然维持ACID的事务特性。有两种方法能够做到这点。第一种方法是将数据库组织成为许多粗粒度的“虚拟”(即逻辑)分区,并分布到各个物理节点上。这样当DBMS需要重新平衡的时候,它可以将虚拟分区在节点间移动。Clustrix和AgilData使用了这种方法,NoSQL中的Cassandra和DynamoDB也使用了这种方法。另一种方法是DBMS通过范围分区重新分布单个元组或多个元组来执行更细粒度的重新平衡。 这类似于MongoDB NoSQL DBMS中的自动分片功能。 ScaleBase和H-Store等使用了这种方法。
4.3 并发控制
并发控制方案是事务处理DBMS中最突出和最重要的实现细节,因为它影响系统几乎所有的方面。并发控制允许最终用户通过多个程序访问数据库,而每个程序在都认为自己运行在专用数据库上。这一点非常重要,因为它提供了系统的原子性和隔离性保证,并由此影响了整个系统的行为。
除了系统并发控制方案外,分布式DBMS的设计的另一个重要方面是该系统使用集中式还是分散式事务协调协议。在集中式协调系统中,所有的事务操作都必须通过*协调器,它负责决定事务是否得以执行。1970-1980年代的事务处理监控器(例如IBM的CICS,Oracle的Tuxedo)中采用了这种方法。而在分散式的协调系统中,每个节点维护访问其数据的事务的状态。节点之间相互协调来确定事务是否有冲突。分散式协调器具有更好的可扩展性,但为了产生和维护事务的全局顺序,DBMS的所有节点都需要与同一个高精度时钟保持同步。
1970-1980年代的第一代分布式DBMS系统使用了二阶段锁(two phase-locking,2PL)方案。SDD-1项目是第一个专用于由集中式协调器管理无共享节点集群中的分布式事务处理的DBMS。IBM的R类似于SDD-1,但是它的主要区别在于R系统的协调器是完全分散式的,它使用了分布式的2PL协议,这样事务可以锁定正在访问的节点中的数据项。INGRES的分布式版本中同样采用了分散的2PL和集中式的死锁监测。
几乎所有基于新架构的NewSQL系统都没有使用2PL,因为处理死锁问题的复杂度太高。当前的趋势是使用时间戳顺序并发控制的变体,其中DBMS假定那些违反串行顺序的事务不会执行交错的数据操作。在NewSQL系统中使用最广泛的协议是分散式的多版本并发控制(multi-version concurrency control, MVCC)。其中DBMS会在数据元组被事务更新时创建新的副本。维护多个版本的方案使事务即使是在其他事务同时更新相同数据时也能够成功地完成,也避免了长时间运行的只读事务阻塞写入操作。这个协议被多数基于新架构的NewSQL系统所采用,例如MemSQL, HyPer,HANA,CockroachDB等。虽然这些系统在实现MVCC的细节上使用了不同的工程方法进行优化,但是这个方案的基本概念并不是新的。MVCC最早是由在一篇MIT的博士论文中提出来的,第一个使用它的商业DBMS是1980年代Digital的VAX Rdb和InterBase。我们注意到InterBase的架构是由Jim Starkey设计的,他同时也是NuoDB最早的设计者,也是失败的Falcon MySQL存储引擎项目的设计者。
其他的系统使用了2PL和MVCC的组合方案。这种方案中事务仍然需要在2PL模式下请求锁来更新数据库,而同时当一个事务修改了一条记录时,DBMS也为这条记录创建一个副本。这个方案使只读查询可以避免请求锁,因此不会阻塞写事务。这个方法最著名的实现是MySQL的InnoDB。另外还有Google的Spanner,NuoDB,Clustrix也都用了这个方法。NuoDB改进了原始的MVCC,它使用gossip协议在节点间广播版本信息。
所有的中间件和DBaaS服务都继承了它们底层DBMS架构使用的并发控制方案,因为大部分都使用MySQL作为底层DBMS,所以大部分的都是使用的2PL加上MVCC方案。
我们认为Spanner(及其后代F1和SpannerSQL)中的并发控制实现是最新颖的NewSQL系统之一。实际方案本身是QQ号出售平台地图基于2PL和MVCC组合,但Spanner最大的不同是使用了硬件设备(例如GPS和原子时钟)来做高精度时钟同步,为事务分配时间戳,通过广域网络实施其多版本数据库的一致视图。CockroachDB声称会提供与Spanner一样的跨数据中心的事务一致性,但不使用原子钟。 它们依赖于混合时钟协议,该协议组合了松散同步的硬件时钟和逻辑计数器。
Spanner引人注目的另一个原因是它预示着Google将在最关键的服务中重新使用交易。 Spanner的作者甚至表示,最好让他们的程序员去处理由于过度使用事务造成的性能问题,而不是像NoSQL DBMS那样编写代码来处理事务的缺失。
最后,唯一没有使用MVCC及其变体的商业NewSQL DBMS是VoltDB。它仍在使用TO并发控制,不像MVCC那样交错执行事务,它通过调度使每个分区一次只有一个事务被执行。它还使用一种混合架构,其中单分区事务以分散方式调度,但多分区事务使用集中式协调器调度。VoltDB通过逻辑时间戳对事务进行排序,然后调度它们以便在轮到它们时在分区上执行。当事务在一个分区上执行时,它对该分区中的所有数据具有独占访问,因此系统不必在其数据结构上设置细粒度的锁和锁存器。因为没有来自其他事务的竞争,那些必须访问单个分区的事务得以有效地执行。基于分区的并发控制的缺点是,如果事务跨越多个分区,它不能很好地工作,因为网络通信延迟会导致节点在等待网络消息时处于空闲状态。这种基于分区的并发控制也不是新的想法。它的早期变体首先在1992年Hector Garcia-Molina的文章中提出,并在1990年代末在kdb系统和HStore(VoltDB的学术版本的前身)中得以实现。
综上,我们发现除了值得称道的工程方法使这些算法在现代硬件和分布式操作环境中更为高效外,NewSQL系统中的核心并发控制方案没有任何显著的新特点。
4.4 次级索引
次级索引包含来自表的不同于其主键的属性集。它允许DBMS支持主键和分区键以外的快速查询。当整个数据库位于单个节点上时,在非分区DBMS中支持它们是没有太多意义的。但是在分布式DBMS中,不会总是以正好需要的属性值进行分区。举例来说,假设数据库根据客户表的主键进行了分区。但是可能会有一些情况希望通过客户的email地址反向查询客户的账户。因为数据库是按照客户主键进行的分区,DBMS不得不将这个查询广播到所有节点,这明显效率非常低下。
在分布式DBMS中支持次级索引有两个设计决策:1)系统在哪里存储它们 2)如何由事务上下文维护他们。在使用集中式协调器的系统中,类似数据分片中间件,次级索引可以同时放在协调器节点和分片节点。这个方法的好处是整个系统中只有一个版本的索引,更加容易维护。
所有基于新架构的NewSQL 系统都是分散式的,使用的是分区的次级索引。意思是说每个节点存储了索引的一部分,而不是一个完整的副本。分区索引和复制完整索引之间的折衷是,前面的查询可能需要跨越多个节点来找到他们正在寻找的东西,但是如果事务更新索引,它将只需要修改一个节点。 在复制索引中,情况正好相反:查找查询可以仅由集群中的一个节点满足,但是任何时候事务修改次级索引关联的数据, DBMS必须执行一个分布式事务来更新索引所有副本。
Clustrix使用分散次级索引,将上述概念混合在一起。DBMS在每个节点上维护一个粗粒度(基于范围的)的索引的副本,而节点将索引值映射到分区。映射使用表分区属性之外的其他属性,这样DBMS可以利用映射关系将查询路由到适当的节点。因为次级索引将精确值映射到数据元组,于是查询通过索引就可以访问数据元组。这种两层的方法仅仅映射范围而不是单个的值,减少了保持索引副本在集群中同步所需的调度次数。
在使用不支持次级索引的NewSQL DBMS的过程中,开发人员创建次级索引最常见方法是使用内存中的分布式缓存(如Memcached)来部署索引。 但是使用外部系统需要应用程序来维护缓存,因为DBMS不会自动更新外部缓存。
4.5 复制
客户为其OLTP应用保证数据的高可用性和持久性的最好的方法是复制数据库。所有现代的DBMS,包括NewSQL系统,都支持某种机制的复制。DBaaS有一个突出的优势是它将所有复制配置的细节都对客户隐藏,因此部署一个DBMS的副本变得极为简单,用户无需关心日志是否传输成功,数据是否同步。
在数据复制中有两个设计决策。第一个是DBMS如何使数据保持节点间的一致性。在强一致的DBMS中,事务的写入必须在被确认提交(即持久化)之前被确认并被安装到所有副本。这种方法的好处是副本可以提供只读的查询并且仍保持一致性。也就是说,当应用收到了事务提交的确认,则该事务对数据库的任何修改对于后续所有的事务都是可见的,无论它们访问哪一个DBMS节点。同时,这样意味着如果一个副本失效,系统并不会丢失任何更新,因为其他所有的节点都是同步的。但是维护这样的同步需要DBMS使用原子提交协议(例如两阶段提交)来确保所有的副本与事务的执行结果一致,而这带来了额外的开销,并且如果节点失败或者有网络分区延迟则,也可能导致系统停滞。这就是为什么NoSQL系统选择弱一致性模型(也称为最终一致性),其中并非所有副本都必须在DBMS通知应用程序写入成功之前确认修改。
我们所知道的所有NewSQL都支持强一致性复制。但是在系统如何保证一致性方面并没有任何创新。在1970年代研究了DBMS的状态机复制的基本原理。NonStop SQL是在1980年代构建的第一代分布式DBMS之一,它就使用了相同的强一致性复制提供容错能力。
除了DBMS将更新传播到副本的策略之外,还有两种不同的执行模型用于决定DBMS如何执行此传播。第一种是主动-主动复制,其中每个节点同时处理相同的请求。例如,当事务执行查询时,DBMS在所有副本处并行执行该查询。这不同于主动-被动复制,首先在单个节点处理请求,然后DBMS将所得状态传送到其他副本。大多数NewSQL DBMS实现第二种方法,因为它们使用非确定性并发控制方案。这意味着它们不能向副本发送查询,因为它们可能在不同副本上以不同的顺序执行,并且数据库的状态将在每个副本处出现分歧。因为执行顺序取决于很多因素,包括网络延迟,缓存停滞,时钟偏差等。
另一方面,确定性DBMS(例如,H-Store,VoltDB,ClearDB)不执行这些附加的协调步骤。这是因为这些DBMS要保证事务的操作在每个副本上以相同的顺序执行,从而保证数据库的状态相同。VoltDB和ClearDB还确保应用程序不会执行那些使用外部信息源的查询,因为这些信息在每个副本上可能是不同的(例如,将时间戳字段设置为本地系统时钟)。
另一个NewSQL系统的独特之处是通过广域网WAN来进行复制。这是现代操作环境的副产品,因为现在很少在远距离的数据中心之间部署系统。所有的NewSQL DBMS都可以通过配置实现广域网上的同步复制,但是这也会引起正常操作中很明显的延迟,所以异步复制的方式更为流行。据我们所知,NewSQL系统中只有Spanner和CockroachDB能提供广域网上强一致副本的复制方案。Spanner使用了原子钟和GPS来做时间同步,而CockroachDB使用的是混合时钟方案。
4.6 崩溃恢复
NewSQL系统容错功能的一个重要特征是使用了崩溃恢复机制。传统的DBMS容错方案的重点是保障数据的更新不会丢失,而NewSQL DBMS除了这点以外,还希望最小化停机时间。现代的Web应用希望能够一直保持在线,因为停机带来的成本实在是太大了。
单节点无备份系统中恢复的传统方法是,在DBMS修复后重新联机,它将加载从磁盘取得的最后一个检查点,然后重播其写入日志(write-ahead log, WAL)以使数据库到达崩溃前那一刻的状态。这种方法的经典实现被称为ARIES,是IBM研究人员在1990年代发明的。 所有主流的DBMS都使用了ARIES的一些变体来实现故障恢复。
在有副本的分布式DBMS中,不能直接使用传统的单节点方法,因为当主节点崩溃时,系统将会自动提升某个从节点充当新的主节点,而之前崩溃的主节点重新联机后,因为DBMS已经有了新的数据,数据库并不停留在崩溃之前的状态,所以主节点不能直接从自己的检查点中恢复数据。恢复的节点需要从新的主节点或者其他副本中更新自己的数据,弥补在停机这段时间内缺失的数据。有两种方法来做这个事情:第一是恢复的节点仍然从自身的存储中加载最后的检查点和写入日志,然后从其他节点读取缺失的日志部分。如果这个节点处理日志的速度比数据更新快,节点上的数据最终会达到与其他节点上的副本相同的状态。如果DBMS使用物理日志,那么这种方法就是可行的,因为将日志更新直接应用到元组的时间远小于执行原始SQL语句所需的时间。另一种方法可以减少恢复的时间,即节点重新联机时丢弃其检查点,让系统给它另一个新的检查点,然后从这个点开始恢复。这种方法带来的一个额外的好处是,系统中加入新的副本节点时也可以用同样的机制。
中间件和DBaaS系统依靠底层单节点DBMS的内建机制来实现故障恢复,不过都增加了额外的主节点选择和其他管理能力。基于全新架构的NewSQL系统结合现成的组件(例如ZooKeeper, Raft)和他们实现的已有算法来做这类事情。所有这些都是自1990年代以来在商业分布式系统中可用的标准程序和技术。
- 未来趋势
我们预计,在不久的将来,数据库应用程序的下一个趋势是能够对新获取的数据执行分析查询和机器学习算法。这种通常也称为“实时分析”或者“混合事务分析处理(hybrid transaction-analytical processing,HTAP)”的应用通过分析新数据和历史数据的组合来进行知识推断,获得洞察力。比传统的商业智能只能基于历史数据进行操作要更为先进。对于现代应用来说,更短的周转时间非常重要,因为数据的价值在其创建时非常巨大,但随着时间推移逐渐减少。
在数据库应用里有三个方法支持HTAP。最为常见的一个方法是部署另一个DBMS,让其中一个专门处理事务,另一个处理分析查询。在这个架构下,前端的OLTP DBMS存储所有由事务创建的新数据,而在后端,系统使用抽取与转换(ETL,extract-transform-load)工具将数据从OLTP DBMS导入到另一个后台的数据仓库DBMS。应用在后端执行所有的复杂的OLAP查询,避免拖慢OLTP系统。所有在OLAP系统中产生的新数据也将会被推送到前端的DBMS中。
被称为λ架构的另一种主流系统设计是使用单独的批处理系统(例如,Hadoop,Spark)来计算历史数据视图,同时使用流处理系统(例如,Storm,Spark Streaming)来提供输入数据视图。在这个分离式的架构中,批处理系统周期性地对数据集进行重新扫描,并将结果批量上传到流处理系统,然后流处理系统将基于新的更新进行修改。
这两种方法都有一些固有的问题。最重要的一点是,在两个分离系统中进行数据传输的时间通常以分钟甚至小时来计算,而且在数据传输时应用程序不能进行数据处理。第二个问题是,部署和维护两种不同DBMS的管理开销巨大,因为人工成本占整个大规模数据库系统成本的的50%左右。
如果想要合并来自不同数据库的数据,还需要应用程序开发人员为多个系统编写查询语句。一些系统试图通过隐藏分离系统架构伪装成单个平台,例如Splice Machine,但是这种方法还有其他技术问题,因为在OLTP系统(Spark)中使用它之前,需要复制来自OLTP系统(Hbase)的数据。
第三个我们认为更好的方法是使用单个HTAP DBMS,它既支持OLTP工作负载的高吞吐量和低延迟需求,又允许在热数据(事务)和冷数据(历史数据)上运行复杂的长时间运行的OLAP查询。 这些较新的HTAP系统与传统的通用DBMS不同的是,它们结合了最近十年来在OLTP(例如,内存存储,无锁执行)和OLAP(例如,列式存储,矢量化执行 )领域的技术积累,而且只需要一个DBMS。
SAP HANA和MemSQL是最早的两个声称自己是HTAP系统的NewSQL DBMS。HAHA在内部使用多个执行引擎,一个用于更适合事务的行数据,另一个用于更适合于分析的列数据。MemSQL使用两个不同的存储管理器(一个管理行,一个管理列),但是混合在同一个执行引擎中。
HyPer原本使用H-Store风格的用于处理OLTP的并发控制。它切换到了带有MVCC的HTAP列存储体系结构,于是可以支持更复杂的OLAP查询。VoltDB甚至将他们的市场宣传策略从纯粹的OLTP性能转向提供流式语义。类似地还有S-Store项目,在H-Store架构之上增加了对流式处理操作的支持。始于2000年代中期的OLAP系统(例如,Greenplum)很可能将开始增强对OLTP的支持。
我们注意到HTAP DBMS的兴起意味着巨大的整体式OLAP数据仓库的衰落。这样的系统在短期内仍然是必要的,因为它们是所有前端OLTP应用孤岛通用的后端数据库。 但是最终数据库技术的发展将允许用户执行跨越多个OLTP数据库(甚至包括多个供应商)的分析查询,而不需要移动数据。
- 结论
我们分析的主要结果是,NewSQL数据库系统并不是与现有的系统架构完全不同的新物种,而是代表数据库技术不断发展的下一篇章。 这些系统使用的大多数技术已经存在于学术界和工业界的先前DBMS中很多年。但是以前这些技术只是独立地在某些系统中得到实现,因此NewSQL DBMS的创新之处在于它们将这些想法纳入了单一平台,而且人们付出了巨大的工程努力,作出了很多创新性的工作。虽然NewSQL DBMS是伴随着更廉价而丰富的计算资源出现的,但它们的应用范围和应用前景也因此而更为广泛。
同样有趣的是考虑NewSQL DBMS潜在的影响和未来的方向。鉴于传统的DBMS提供商的市场地位牢不可破,资金充足,NewSQL系统只能通过艰难的战斗赢得市场地位。在过去的五年中,一些NewSQL公司已经关闭(例如GenieDB,Xeround,Translattice)或者转向重点关注其他问题域(例如ScaleBase,ParElastic)。基于我们对一些公司的的分析和访谈,我们发现NewSQL系统的采用率相对较低,尤其是与开发人员驱动的NoSQL相比的时候。这是因为NewSQL DBMS的设计目标是支持事务性的工作负载,而这些应用大多数是企业应用。与Web应用相比企业应用对于数据库的选择更加保守。另外我们也发现NewSQL DBMS用于补充或者替换现有的RDBMS,但NoSQL通常用于新业务系统的开发。
2000左右OLAPL DBMS刚刚兴起的时候,大部分开发商都被主要的技术公司收购。而NewSQL领域里目前还只有一家公司被收购。在2016年3月,Tableau宣布它收购了HyPer项目的初创公司。另外两个可能的例外是:1)2015年3月苹果公司收购了FoundationDB,但是我们把它排除在外,因为这个系统底层是NoSQL的Key-Value存储,上面只有一层效率低下的SQL层;2)ScaleArc收购了ScaleBase,但这起收购案发生在竞争对手之间。这些案例中没有一个是传统巨头收购新兴公司的情况(例如2011年,Teradata收购Aster Data System)。反过来,我们看到巨头们更愿意在自己的系统上进行改进和创新,而不是去收购初创的NewSQL公司。2014年Microsoft在SQLServer上新增了内存Hekaton引擎来增强OLTP处理能力。Oracle和IBM的创新进度比较慢,他们最近才为系统添加了列存储扩展,与新兴的OLAP DMBS(例如HP Vertica和Amazon Redshift)展开竞争,并有可能在未来推出内存中的OLTP工作负载处理系统。
从更长期来看,我们将数据库的发展归纳为四类:1)始于1980-1990年代的传统DBMS;2)始于2000年代的OLAP数据仓库;3)始于2000年代的NoSQL DBMS,以及4)始于2010年代的NewSQL。我们希望在这些分类中所有的核心系统将会支持某种形式的关系模型和SQL(即使它们还没有),并且会像HTAP DBMS一样同时支持OLTP操作和OLAP查询。当这一天到来时,这些标签将成为历史。
(完)