云计算下的数据库 分析 以及部分互联网公司目前采用的新型数据库总结

云计算下的新型数据库技术 

 

摘要:在这个信息化的时代,我们的一举一动都离不开与数据打交道,特别是云计算和大数据时代的到来,使得传统数据库的性能已无法满足海量数据的实时交易查询需求,在性能和成本的双重压力之下,云计算下的数据库需要寻找突破之路。

 

 1.简介:

云计算通过整合,管理和调配分布在互联网中的所有计算资源,以统一的界面同时向用户提供服务。互联网提供的各种计算形式的应用以及提供这些服务的数据中心和软硬件基础设施、提供的服务成为软件即服务(SaaS),数据中心的软硬件基础设施即为云,这种虚拟化资源提供计算的方式使得服务通过互联网传播,而用户不需要知道云计算服务的提供者和提供方式。因此,云计算具有规模大,可靠性高,用户透明,可扩展性强,提供按需服务和廉价等特点。而实现以上需求的前提条件就是云计算系统应该具备足够大的规模和处理能力,以满足大量的数据访问,数据存储和来自不同网络等额请求。

传统的关系型数据库虽然在数据存储方面占据着不可动摇的地位,但由于其天生的限制,越来越不能满足云计算下的数据扩展、读写速度、支撑容量以及建设和运营成本的要求。鉴于此,国内外知名的一些互联网企业GoogleFacebookTwitter、阿里、腾讯、百度等纷纷展开探索,自主研发新型数据库,这些企业有拥有众多的优秀人才,以及丰富的产品经验,所以对于新型数据库的探索成果在一定程度上也代表了当下云计算下数据库的最新的进展,所以本文主要先对与传统型数据库的优劣进行一些分析,接着介绍了现如今新型数据库的研究进展,对各类型数据库进行一些对比分析,最后在对于还存在的不足进行总结并对数据库的发展提出自己一些的看法。

2.背景:

2.1 云计算和大数据:

大数据是一种大规模数据的管理和利用的商业模式和技术平台的泛指,它不同于传统的海量数据,除了数据规模呈现几何级数增长的特征以外,还包括所有数据类型的采集、分类、处理、分析和展现等多个方面,从而最终实现从大数据中挖掘潜在巨大价值的目的。因此,大数据具有这4方面的特征:规模性(Volume)、多样性(Variety)、高速性(Velocity)和真实性(Veracity)。

云计算是一种基于互联网的计算方式,通过这种方式,共享的软硬件资源和信息可以按需提供给计算机和其他设备。能够像煤气、水电一样提供给信息时代的社会化服务,使用方便,费用低廉。云计算具有以下的特点:

(1) 超大规模。“云”具有超大的规模,Google云计算拥有100多万台服务器,AmazonIBM、微软等的云均拥有几十万台服务器,正是这样拥有超大规模的“云”能够赋予用户前所未有的计算能力。

(2) 虚拟化。云计算支持用户在任意位置,使用各种终端获取应用服务。所请求的资源来自“云”,而不是固定的有形的实体。应用在“云”中某处运行,但实际用户无需了解、也不用担心应用运行的具体位置。只需要一台笔记本或者一部手机,就可以通过网络服务来实现我们需要的一切,甚至包括超级计算的任务。

(3) 高可靠性。“云”使用了数据多副本容错、计算节点同构可互换等措施来保障服务的高可靠性,使用云计算比使用本地计算可靠。

(4) 通用性。云计算不针对特定的应用,在云的支撑下可以构造出千变万化的应用,同一个云可以同时支撑不同的应用运行

(5) 高可扩展性。云的规模可以动态伸缩,满足应用和用户规模增长的需要。

(6) 按需服务。云是一个庞大的资源池,可按需购买,象自来水,电,煤气一样计费使用。

(7) 极其廉价。用于“云”的特殊容错措施可以采用极其廉价的节点来构成云,“云”的自动化集中式管理使得大量企业无需负担日益高昂的数据中心管理成本,“云”的通用性使资源的利用率较之传统系统大幅提升,因此用户可以充分享受“云”的低成本优势。

 

 

大数据着眼于“数据”,关注实际业务,提供数据采集分析挖掘,看重信息积淀即数据存储能力。云计算着眼于“计算”,关注IT解决方案,提供IT基础架构,看重计算能力,即数据处理能力,数据是两者之间最重要的联系,也是两者存在的意义,所以对于云计算和大数据时代,数据库技术的重要性也就不言而喻了。

2.2 云计算下的传统型数据库

随着web2.0的发展,传统的关系型数据库在应对超大规模和高并发的数据量和访问量时存在难以克服的问题:

(1)高并发读写速度慢

在数据量达到一定规模时,由于关系型数据库的系统逻辑非常复杂,使得其容易发生死锁等并发问题,导致其读写速度下降非常严重。

(2)支撑容量有限

对于数据量巨大的一些网站例如社交网站,每天海量的用户动态,累计下每月就能产生几亿条数据记录,对于关系型数据库,在这样一个具有数亿条记录的表中进行SQL查询,效率会是极其低下乃至不可忍受的。

(3)可扩展性差

在基于web的架构中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,传统的关系型数据库却不能像web service 那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,因此迫切需要关系数据库也能够通过不断添加服务器节点来实现扩展。

(4)建设和运维成本高

企业级数据库的价格很高,并且随着系统的规模增大而不断上升。高昂的建设和运维成本无法满足云计算应用对数据库的需求。

(5)对于分布式系统的制约

为了支撑更大的访问量和数据量,我们必然需要分布式数据库系统,然而由于传统关系型数据库的强一致性,就会使得分布式系统的延迟提高,因为网络通信本身比单机内通信代价高很多,这种通信的代价就会直接增加系统单次提交的延迟。延迟提高会导致数据库所持有时间变长,使得高冲突条件下分布式事物的性能不升反降,甚至性能距离单机数据库都还有明显的差距。面对这个难题,传统的关系数据库选择了放弃分布式的方案,因为在20世纪70-80年代,数据库主要被用来处理企业内的各类数据,面对的用户不过几千人,而数据量最多也就是TB级别。用单台机器处理事务,用个磁盘阵列处理一下磁盘容量不够的问题,基本就能解决一切问题。

然而,在大数据时代,云计算的数据量已然从TB级别变为了PB级别甚至更多,存在单点的单击系统无论如何努力,都会面对系统处理能力的天花板,原来的这条路就不能再接着走下去了。

2.3 几种云计算下的新型数据库及其实现原理

 

(1)NoSQL非关系型数据库

面对传统数据库出现的种种挑战,NoSQL是在新形势下出现的一种给关系型数据库的总称,它用全新的存储方式,减少了数据交互,减少了编写、调试的代码,对海量数据实现高效存储和高效访问,同时它的开源免费也降低了企业的运营成本。

NoSQL的主要特征为:

1)不需要预定义模式:不需要预定义数据模式,预定义表结构。数据中的每条记录可能有不同的属性和格式。当插入数据时,并不需要预先定义它们的模式。 

2无共享架构:相对于将所有数据存储的存储区域网络中的全共享架构。NoSQL往往将数据划分后存储在各个本地服务器上。因为从本地磁盘读取数据的性能往往好于通过网络传输读取数据的性能,从而提高了系统的性能。

3弹性可扩展:可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移。

4分区:相对于将数据存放于同一个节点,NoSQL数据库需要将数据进行分区,将记录分散在多个节点上面。并且通常分区的同时还要做复制。这样既提高了并行性能,又能保证没有单点失效的问题。

5异步复制:RAID存储系统不同的是,NoSQL中的复制,往往是基于日志的异步复制。这样,数据就可以尽快地写入一个节点,而不会被网络传输引起迟延。缺点是并不总是能保证一致性,这样的方式在出现故障的时候,可能会丢失少量的数据。

6BASE相对于事务严格的ACID特性,NoSQL数据库保证的是BASE特性。BASE是最终一致性和软事务。

NoSQL数据库并没有一个统一的架构,两种NoSQL数据库之间的不同,甚至远远超过两种关系型数据库的不同。可以说,NoSQL各有所长,成功的NoSQL必然特别适用于某些场合或者某些应用,在这些场合中会远远胜过关系型数据库和其他的NoSQL

具体优势表现有:

1)数据库的开发效率高,在设计上NoSQL数据库和传统的数据库有很大的不同,传统应用程序的开发中,需要在内存数据结构和福安息数据库的映射上花费大量的精力和时间。NoSQL数据库更符合应用程序的需求,部分NoSQL数据库可以在硬盘上直接操作,简化了数据的交互,减少了编写、调试程序的工作量。

2)数据库的扩展能力强。现在企业通常使用更小,更便宜的计算机组成集群来构建数据库,NoSQL数据库的设计正是针对服务器集群,所以更适合大规模数据的处理。

3)数据库的开发成本低廉。因为NoSQL数据库主要都是开源软件,所以没有昂贵的开发成本。在项目开发中很多企业为了节省开发成本而选择NoSQL数据库。

4)数据模型灵活。在关系数据库中,数据有固定结构,通过各种操作互相关联,对大型的表格增删字段非常麻烦。NoSQL的存储只有一对键值或者数组,无需事先建立字段,任何时候都可以存储自定义的数据格式。

NoSQL数据库的分类

键值(Key-Value)存储数据库

这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。[3] 举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.

列存储数据库。

这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.

文档型数据库

文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。

图形(Graph)数据库

图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API如:Neo4J, InfoGrid, Infinite Grap

(2)NewSQL

NewSQL是对各种新的可扩展/高性能数据库的总称,这类数据库不仅具有NoSQL对海量数据的存储管理能力,还有传统数据库支持ACID和SQL等特性。

NewSQL系统虽然在的内部结构变化很大,但是它们有两个显着的共同特点:

(1)它们都支持关系数据模型;

(2) 它们都使用SQL作为其主要的接口。已知的第一个NewSQL系统叫做H-Store,它是一个分布式并行内存数据库系统。

目前NewSQL系统大致分三类: 

新架构

第一类型的NewSQL系统是全新的数据库平台,它们均采取了不同的设计方法。它们大概分两类:

(1) 这类数据库工作在一个分布式集群的节点上,其中每个节点拥有一个数据子集。 SQL查询被分成查询片段发送给自己所在的数据的节点上执行。这些数据库可以通过添加额外的节点来线性扩展。现有的这类数据库有: Google Spanner, VoltDB, Clustrix, NuoDB.

(2) 这些数据库系统通常有一个单一的主节点的数据源。它们有一组节点用来做事务处理,这些节点接到特定的SQL查询后,会把它所需的所有数据从主节点上取回来后执行SQL查询,再返回结果。

SQL引擎

第二类是高度优化的SQL存储引擎。这些系统提供了MySQL相同的编程接口,但扩展性比内置的引擎InnoDB更好。这类数据库系统有:TokuDB, MemSQL。

透明分片

这类系统提供了分片的中间件层,数据库自动分割在多个节点运行。这类数据库包扩:ScaleBase,dbShards, Scalearc。 

2.4 当今几家主流互联网公司的数据库技术

(1)阿里分布式数据库服务DRDS

DRDS也是一个NewSQL的系统,它与ScaleBase、VoltDB等系统类似,都希望能够找到一条既能保持系统的高扩展性和高性能,又能尽可能保持传统数据库的ACID事务和SQL特性的分布式数据库系统。

 

三层架构,Matrix对应数据库切分场景,对SQL有一定限制,Group对应读写分离和高可用场景,对SQL几乎没有限制。

 

DRDS主要功能介绍

分布式SQL执行引擎
分布式SQL引擎主要的目的,就是实现与单机数据库SQL引擎的完全兼容。目前我们的SQL引擎能够做到与MySQL的SQL引擎全兼容,包括各类join和各类复杂函数等。他主要包含SQL解析、优化、执行和合并四个流程,如图3中绿色部分。

 

虽然SQL是兼容的,但是分布式SQL执行算法与单机SQL的执行算法却完全不同,原因也很简单,网络通信的延迟比单机内通信的延迟大得多。举个 例子说明一下,我们有份文件要从一张纸A上誊写到另外一张纸B上,单机系统就好比两张纸都在同一个办公室里,而分布式数据库则就像是一张纸在北京,一张纸 在杭州。
自然地,如果两张纸在同一个办公室,因为传输距离近,逐行誊写的效率是可以接受的。而如果距离是北京到杭州,用逐行誊写的方式,就立刻显得代价太 高了,我们总不能看一行,就打个“飞的”去杭州写下来吧。在这种情况下,还是把纸A上的信息拍个照片,【一整批的】带到杭州去处理,明显更简单一些。这就 是分布式数据库特别强调吞吐调优的原因,只要是涉及到跨机的所有查询,都必须尽可能的积攒一批后一起发送,以减少系统延迟提高带来的不良影响。

按需数据库集群平滑扩缩

DRDS允许应用按需将新的单机存储加入或移出集群,DRDS则能够保证应用在迁移流程中实现不停机扩容缩容。

 

在内部的数据库使用实践中,这个功能的一个最重要应用场景就是双11了。在双11之前,会将大批的机器加入到我们的数据库集群中,抗过了双11,这批机器就会下线。 

因为完全无法预测在什么时间点系统会有爆发性的增长,而如果在这时候系统因为技术原因不能使用,就会给整个业务带来毁灭性的影响,风口一旦错过,就追悔莫及了。我想这就是云计算特别强调可扩展能力的原因吧。

小表广播
小表广播也是我们在分布式数据库领域内最常用的工具之一,他的核心目的其实都是一个——尽可能让查询只发生在单机。

让我们用一个例子来说明,小表广播的一般使用场景。

 

图中,如果我想知道买家id等于0的用户在商城里面买了哪些商品,我们一般会先将这两个表join起来,然后再用where平台名=”商城” and buyerID = 0找到符合要求的数据。然而这种join的方式,会导致大量的针对左表的网络I/O。如果要取出的数据量比较大,系统延迟会明显上升。

这时候,为了提升性能,我们就必须要减少跨机join的网络代价。我们比较推荐应用做如下处理,将左表复制到右表的每一个库上。这样,join操作就由分布式join一下变回到本地join,系统的性能就有很大的提升了,如图所示。

 

分布式事务套件

在阿里巴巴的业务体系中存在非常多需要事务类的场景,下单减库存,账务,都是事务场景最集中的部分。
而我们处理事务的方法却和传统应用处理事务的方案不大一样,我们非常强调事务的最终一致性和异步化。利用这种方式,能够极大地降低分布式系统中锁持有的时间,从而极大地提升系统性能。

 

这种处理机制,是我们分布式事务能够以极低成本大量运行的最核心法门。在DRDS平台内,我们将这些方案产品化,为了DRDS的分布式事务解决套件。

利用他们,能够让你以比较低的成本,实现低延迟,高吞吐的分布式事务场景。

 

(2)MongoDB

MongoDB[1] 是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB[2] 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:

*面向集合存储,易存储对象类型的数据。

*模式自由。

*支持动态查询。

*支持完全索引,包含内部对象。

*支持查询。

*支持复制和故障恢复。

*使用高效的二进制数据存储,包括大型对象(如视频等)。

*自动处理碎片,以支持云计算层次的扩展性。

*支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。

*文件存储格式为BSON(一种JSON的扩展)。

*可通过网络访问。

使用原理

所谓面向集合Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)Nytro MegaRAID技术中的闪存高速缓存算法,能够快速识别数据库内大数据集中的热数据,提供一致的性能改进。

模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。

存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各种复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized Document Format)。[3] 

[4] MongoDB已经在多个站点部署,其主要场景如下:

1)网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。

2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。

3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。

不适用的场景如下:1)要求高度事务性的系统。

2)传统的商业智能应用。

3)复杂的跨文档(表)级联查询。

设计特征

MongoDB 的设计目标是高性能、可扩展、易部署、易使用,存储数据非常方便。其主要功能特性如下。

1)面向集合存储,容易存储对象类型的数据。在MongoDB 中数据被分组存储在集合中,集合类似RDBMS 中的表,一个集合中可以存储无限多的文档。

2)模式自由,采用无模式结构存储。在MongoDB 中集合中存储的数据是无模式的文档,采用无模式存储数据是集合区别于RDBMS 中的表的一个重要特征。

3)支持完全索引,可以在任意属性上建立索引,包含内部对象。MongoDB的索引和RDBMS 的索引基本一样,可以在指定属性、内部对象上创建索引以提高查询的速度。除此之外,MongoDB 还提供创建基于地理空间的索引的能力。

4)支持查询。MongoDB 支持丰富的查询操作,MongoDB 几乎支持SQL中的大部分查询。

5)强大的聚合工具。MongoDB 除了提供丰富的查询功能外,还提供强大的聚合工具,如countgroup 等,支持使用MapReduce 完成复杂的聚合任务。

6)支持复制和数据恢复。MongoDB 支持主从复制机制,可以实现数据备份、故障恢复、读扩展等功能。而基于副本集的复制机制提供了自动故障恢复的功能,确保了集群数据不会丢失。

7)使用高效的二进制数据存储,包括大型对象(如视频)。使用二进制格式存储,可以保存任何类型的数据对象。

8)自动处理分片,以支持云计算层次的扩展。MongoDB 支持集群自动切分数据,对数据进行分片可以使集群存储更多的数据,实现更大的负载,也能保证存储的负载均衡。

9)支持PerlPHPJavaC#JavaScriptRubyC++语言的驱动程序,MongoDB 提供了当前所有主流开发语言的数据库驱动包,开发人员使用任何一种主流开发语言都可以轻松编程,实现访问MongoDB 数据库。

10)文件存储格式为BSONJSON 的一种扩展)。BSON 是对二进制格式的JSON 的简称,BSON 支持文档和数组的嵌套。

11)可以通过网络访问。可以通过网络远程访问MongoDB 数据库。

(3)亚马逊自主研发的数据库:DynamoDB

DynamoDB是亚马逊自主研发的NoSQL型数据库,Amazon DynamoDB 是一项快速灵活的 NoSQL 数据库服务,适合所有需要一致性且延迟低于 10 毫秒的任意规模的应用程序。它是完全托管的云数据库,支持文档和键值存储模型。其灵活的数据模型和可靠的性能令其成为移动、Web、游戏、广告技术、物联网和众多其他应用的不二之选。

 

Amazon DynamoDB 优势

 

快速稳定的性能

Amazon DynamoDB 旨在为所有应用程序提供快速稳定、规模弹性的性能。服务端平均延迟通常不超过十毫秒。随着您的数据卷增多,应用程序性能要求增加,Amazon DynamoDB 使用自动分区和 SSD 技术来满足您的吞吐量需求,以任意规模提供低延迟。

高度可扩展

创建表时,只需指定所需的请求容量即可。如果您的应用吞吐量需求发生变化,只需使用 AWS 管理控制台或 Amazon DynamoDB API 调用更新表的请求容量即可。尽管 Amazon DynamoDB 在后台管理所有的扩展工作,您仍然可以在扩展进行过程中达成您的优先吞吐量等级。

 

 

灵活

Amazon DynamoDB 支持文档和键值数据结构,您可以灵活地设计最适合您的应用程序的最佳架构。 

 

精细访问控制

Amazon DynamoDB 与 AWS Identity and Access Management (IAM) 集成,对组织内的用户实现精细的访问控制。您可以为每名用户分配唯一的安全证书,控制每名用户对服务和资源的访问。 

完全托管

Amazon DynamoDB 是完全托管的云 NoSQL 数据库服务,您只需创建数据库表并设置吞吐量,其余事情都交由该服务来代劳。您无需再担心数据库管理任务,例如硬件或软件配置、创建设置和配置、软件更新、操作可靠的分布式数据库集群,或者随着扩展需要在多个实例间对数据进行分区等问题,您只需尽享 Amazon DynamoDB 服务之大成。

(4)FaceBook图形数据库TAO

Facebook上,人们已经形成了一个复杂的社会关系网络,如何去存储、扩展和展示这个网络是Facebook工程师的一大难题。早在几年前,Facebook的工程师就意识到:关系型数据库的老方法,正在逐步降低基础设施和代码的效率。2009年,他们开始设计一种新的数据库体系结构,也就是分布式数据库TAOThe Associations and Objects)。625日,Facebook在官方博客上公布了支持其基础设施细节。

Facebook的软件工程师Mark Marchukov在博客中表示他们之所以创建TAO的原因之一在于同时使用MySQLMemcached读取数据太复杂了。产品工程师要工作在两种完全不同的数据模型之间:大规模的MySQL服务器用关系表存储持久数据,类似数量的缓存数据服务器用来存储SQL查询到的键值对。即便是封装在数据访问库中最常见的操作,也需要产品工程师对系统内部有充分的了解,才能高效地使用memcache-MySQL组合。

TAO的图型架构在信息组织方面类似于Facebook图搜索工具,它将世界看作由节点(对象,即人、地点和事物)和边(关联,即他们之间的关系)组成的图。随着数据量的增大,保持数据的关系模式变得不再重要,TAO及其对应的API应运而生。

Marchukov认为TAO最大的突破在于实现了图解模型,Facebook的主要工作负载在于读取数据,TAO证明了图数据模型很适合这类查询操作较多的网站。实际上,类似Neo4j的图形数据库一直备受关注,因为它能有效表示人际关系。 

Marchukov 在博客中提到,TAO不仅大规模实现了图数据结构,也使用MySQL实现硬盘上的持久存储,同时要保证数据在各个数据中心的最终一致性,用户才能获取新鲜事

TAO服务运行在大量的服务器集群上,这些分布在不同地理位置的集群构成一个树形网络。有另外的集群用来持久存储对象和对象关联,RAM和闪存实现缓存。这种分层结构在单独进行不同类型的集群扩展时更方便,也能有效利用服务器硬件。

(5)Google Spanner简介

Spanner 是Google的全球级的分布式数据库 (Globally-Distributed Database) 。Spanner的扩展性达到了令人咋舌的全球级,可以扩展到数百万的机器,数已百计的数据中心,上万亿的行。更给力的是,除了夸张的扩展性之外,他还能 同时通过同步复制和多版本来满足外部一致性,可用性也是很好的。冲破CAP的枷锁,在三者之间完美平衡。

Spanner是个可扩展,多版本,全球分布式还支持同步复制的数据库。他是Google的第一个可以全球扩展并且支持外部一致的事务。Spanner能 做到这些,离不开一个用GPS和原子钟实现的时间API。这个API能将数据中心之间的时间同步精确到10ms以内。因此有几个给力的功能:无锁读事务, 原子schema修改,读历史数据无block 

下面主要是Spanner的背景,设计和并发控制。

Spanner背景

要搞清楚Spanner原理,先得了解SpannerGoogle的定位。

从上图可以看到。Spanner位于F1GFS之间,承上启下。所以先提一提F1GFS

F1

和众多互联网公司一样,在早期Google大量使用了MysqlMysql是单机的,可以用Master-Slave来容错,分区来扩展。但是需 要大量的手工运维工作,有很多的限制。因此Google开发了一个可容错可扩展的RDBMS——F1。和一般的分布式数据库不同,F1对应RDMS应有的 功能,毫不妥协。起初F1是基于Mysql的,不过会逐渐迁移到Spanner

F1有如下特点:

·        7×24高可用。哪怕某一个数据中心停止运转,仍然可用。

·        可以同时提供强一致性和弱一致。

·        可扩展

·        支持SQL

·        事务提交延迟50-100ms,读延迟5-10ms,高吞吐

众所周知Google BigTable是重要的NoSql产品,提供很好的扩展性,开源世界有HBase与之对应。为什么Google还需要F1,而不是都使用 BigTable呢?因为BigTable提供的最终一致性,一些需要事务级别的应用无法使用。同时BigTable还是NoSql,而大量的应用场景需 要有关系模型。就像现在大量的互联网企业都使用Mysql而不愿意使用HBase,因此Google才有这个可扩展数据库的F1。而Spanner就是 F1的至关重要的底层存储技术。

ColossusGFS II

Colossus也是一个不得不提起的技术。他是第二代GFS,对应开源世界的新HDFSGFS是著名的分布式文件系统。

初代GFS是为批处理设计的。对于大文件很友好,吞吐量很大,但是延迟较高。所以使用他的系统不得不对GFS做各种优化,才能获得良好的性能。那为什么 Google没有考虑到这些问题,设计出更完美的GFS ?因为那个时候是2001年,Hadoop出生是在2007年。如果Hadoop是世界领先水平的话,GFS比世界领先水平还领先了6年。同样的 Spanner出生大概是2009年,现在我们看到了论文,估计SpannerGoogle已经很完善,同时Google内部已经有更先进的替代技术在 酝酿了。笔者预测,最早在2015年才会出现SpannerF1的山寨开源产品。

Colossus是第二代GFSColossusGoogle重要的基础设施,因为他可以满足主流应用对FS的要求。Colossus的重要改进有:

·      优雅Master容错处理 (不再有2s的停止服务时间)

·        Chunk大小只有1MB (对小文件很友好)

·        Master可以存储更多的Metadata(Chunk64MB变为1MB后,Metadata会扩大64倍,但是Google也解决了)

Colossus可以自动分区Metadata。使用Reed-Solomon算法来复制,可以将原先的3份减小到1.5份,提高写的性能,降低延迟。客户端来复制数据。具体细节笔者也猜不出。

 

BigTable, Megastore对比

Spanner主要致力于跨数据中心的数据复制上,同时也能提供数据库功能。在Google类似的系统有BigTableMegastore。和这两者相比,Spanner又有什么优势呢。

BigTableGoogle得到了广泛的使用,但是他不能提供较为复杂的Schema,还有在跨数据中心环境下的强一致性。Megastore 有类RDBMS的数据模型,同时也支持同步复制,但是他的吞吐量太差,不能适应应用要求。Spanner不再是类似BigTable的版本化 key-value存储,而是一个“临时多版本”的数据库。何为“临时多版本”,数据是存储在一个版本化的关系表里面,存储的时间数据会根据其提交的时间 打上时间戳,应用可以访问到较老的版本,另外老的版本也会被垃圾回收掉。

Google官方认为 Spanner是下一代BigTable,也是Megastore的继任者。

 

Google Spanner设计

功能

从高层看Spanner是通过Paxos状态机将分区好的数据分布在全球的。数据复制全球化的,用户可以指定数据复制的份数和存储的地点。 Spanner可以在集群或者数据发生变化的时候将数据迁移到合适的地点,做负载均衡。用户可以指定将数据分布在多个数据中心,不过更多的数据中心将造成 更多的延迟。用户需要在可靠性和延迟之间做权衡,一般来说复制12个数据中心足以保证可靠性。

作为一个全球化分布式系统,Spanner提供一些有趣的特性。

·        应用可以细粒度的指定数据分布的位置。精确的指定数据离用户有多远,可以有效的控制读延迟(读延迟取决于最近的拷贝)。指定数据拷贝之间有多远,可以控制 写的延迟(写延迟取决于最远的拷贝)。还要数据的复制份数,可以控制数据的可靠性和读性能。(多写几份,可以抵御更大的事故)

·        Spanner还有两个一般分布式数据库不具备的特性:读写的外部一致性,基于时间戳的全局的读一致。这两个特性可以让Spanner支持一致的备份,一致的MapReduce,还有原子的Schema修改。

这写特性都得益有Spanner有一个全球时间同步机制,可以在数据提交的时候给出一个时间戳。因为时间是系列化的,所以才有外部一致性。这个很容易理解,如果有两个提交,一个在T1,一个在T2。那有更晚的时间戳那个提交是正确的。

这个全球时间同步机制是用一个具有GPS和原子钟的TrueTime API提供了。这个TrueTime API能够将不同数据中心的时间偏差缩短在10ms内。这个API可以提供一个精确的时间,同时给出误差范围。Google已经有了一个TrueTime API的实现。笔者觉得这个TrueTimeAPI 非常有意义,如果能单独开源这部分的话,很多数据库如MongoDB都可以从中受益。

体系结构

Spanner由于是全球化的,所以有两个其他分布式数据库没有的概念。

·        Universe。一个Spanner部署实例称之为一个Universe。目前全世界有3个。一个开发,一个测试,一个线上。因为一个Universe就能覆盖全球,不需要多个。

·        Zones. 每个Zone相当于一个数据中心,一个Zone内部物理上必须在一起。而一个数据中心可能有多个Zone。可以在运行时添加移除Zone。一个Zone可以理解为一个BigTable部署实例。

 

如图所示。一个Spanner有上面一些组件。实际的组件肯定不止这些,比如TrueTime API Server。如果仅仅知道这些知识,来构建Spanner是远远不够的。但Google都略去了。那笔者就简要介绍一下。

·        Universemaster: 监控这个universezone级别的状态信息

·        Placement driver:提供跨区数据迁移时管理功能

·        Zonemaster:相当于BigTableMaster。管理Spanserver上的数据。

·        Location proxy:存储数据的Location信息。客户端要先访问他才知道数据在那个Spanserver上。

·        Spanserver:相当于BigTableThunkServer。用于存储数据。

可以看出来这里每个组件都很有料,但是Google的论文里只具体介绍了Spanserver的设计,笔者也只能介绍到这里。下面详细阐述Spanserver的设计。

 

Spanserver

本章详细介绍Spanserver的设计实现。Spanserver的设计和BigTable非常的相似。参照下图

从下往上看。每个数据中心会运行一套Colossus (GFS II) 。每个机器有100-1000tabletTablet概念上将相当于数据库一张表里的一些行,物理上是数据文件。打个比方,一张1000行的表,有 10tablet,第1-100行是一个tablet,第101-200是一个tablet。但和BigTable不同的是BigTable里面的 tablet存储的是Key-Value都是stringSpanner存储的Key多了一个时间戳:

(Key: string, timestamp: int64) ->string

因此spanner天生就支持多版本,tablet在文件系统中是一个B-tree-like的文件和一个write-ahead日志。

每个Tablet上会有一个Paxos状态机。Paxos是一个分布式一致性协议。Table的元数据和log都存储在上面。Paxos会选出一个 replicaleader,这个leader的寿命默认是10s,10s后重选。Leader就相当于复制数据的master,其他replica的 数据都是从他那里复制的。读请求可以走任意的replica,但是写请求只有去leader。这些replica统称为一个paxos group

每个leader replicaspanserver上会实现一个lock table还管理并发。Lock table记录了两阶段提交需要的锁信息。但是不论是在Spanner还是在BigTable上,但遇到冲突的时候长时间事务会将性能很差。所以有一些操 作,如事务读可以走lock table,其他的操作可以绕开lock table

每个leader replicaspanserver上还有一个transaction manager。如果事务在一个paxos group里面,可以绕过transaction manager。但是一旦事务跨多个paxos group,就需要transaction manager来协调。其中一个Transactionmanager被选为leader,其他的是slave听他指挥。这样可以保证事务。

 

Directories and Placement

之所以SpannerBigTable有更强的扩展性,在于Spanner还有一层抽象的概念directory, directory是一些key-value的集合,一个directory里面的key有一样的前缀。更妥当的叫法是bucketing。 Directory是应用控制数据位置的最小单元,可以通过谨慎的选择Key的前缀来控制。据此笔者可以猜出,在设计初期,Spanner是作为F1的存 储系统而设立,甚至还设计有类似directory的层次结构,这样的层次有很多好处,但是实现太复杂被摒弃了。

Directory作为数据放置的最小单元,可以在paxos group里面移来移去。Spanner移动一个directory一般出于如下几个原因:

·        一个paxos group的负载太大,需要切分

·        将数据移动到access更近的地方

·        将经常同时访问的directory放到一个paxos group里面

Directory可以在不影响client的前提下,在后台移动。移动一个50MBdirectory大概需要的几秒钟。

那么directorytablet又是什么关系呢。可以理解为Directory是一个抽象的概念,管理数据的单元;而tablet是物理的东 西,数据文件。由于一个Paxos group可能会有多个directory,所以spannertablet实现和BigTabletablet实现有些不同。BigTable的 tablet是单个顺序文件。Google有个项目,名为Level DB,是BigTable的底层,可以看到其实现细节。而Spannertablet可以理解是一些基于行的分区的容器。这样就可以将一些经常同时访问 的directory放在一个tablet里面,而不用太在意顺序关系。

paxos group之间移动directory是后台任务。这个操作还被用来移动replicas。移动操作设计的时候不是事务的,因为这样会造成大量的读写 block。操作的时候是先将实际数据移动到指定位置,然后再用一个原子的操作更新元数据,完成整个移动过程。

Directory还是记录地理位置的最小单元。数据的地理位置是由应用决定的,配置的时候需要指定复制数目和类型,还有地理的位置。比如(上海, 复制2份;南京复制1。这样应用就可以根据用户指定终端用户实际情况决定的数据存储位置。比如中国队的数据在亚洲有3份拷贝日本队的数据全球都有拷贝。

前面对directory还是被简化过的,还有很多无法详述。

 

数据模型

Spanner的数据模型来自于Google内部的实践。在设计之初,Spanner就决心有以下的特性:

·        支持类似关系数据库的schema

·        Query语句

·        支持广义上的事务

为何会这样决定呢?在Google内部还有一个Megastore,尽管要忍受性能不够的折磨,但是在Google300多个应用在用它,因为 Megastore支持一个类似关系数据库的schema,而且支持同步复制 (BigTable只支持最终一致的复制。使用Megastore的应用有大名鼎鼎的Gmail, Picasa, Calendar, Android MarketAppEngine。 而必须对Query语句的支持,来自于广受欢迎的Dremel,笔者不久前写了篇文章来介绍他。 最后对事务的支持是比不可少了,BigTableGoogle内部被抱怨的最多的就是其只能支持行事务,再大粒度的事务就无能为力了。Spanner的 开发者认为,过度使用事务造成的性能下降的恶果,应该由应用的开发者承担。应用开发者在使用事务的时候,必须考虑到性能问题。而数据库必须提供事务机制, 而不是因为性能问题,就干脆不提供事务支持。

数据模型是建立在directorykey-value模型的抽象之上的。一个应用可以在一个universe中建立一个或多个 database,在每个database中建立任意的tableTable看起来就像关系型数据库的表。有行,有列,还有版本。Query语句看起来 是多了一些扩展的SQL语句。

Spanner的数据模型也不是纯正的关系模型,每一行都必须有一列或多列组件。看起来还是Key-value。主键组成Key,其他的列是Value。但这样的设计对应用也是很有裨益的,应用可以通过主键来定位到某一行。

上图是一个例子。对于一个典型的相册应用,需要存储其用户和相册。可以用上面的两个SQL来创建表。Spanner的表是层次化的,最顶层的表是 directory table。其他的表创建的时候,可以用interleave in parent来什么层次关系。这样的结构,在实现的时候,Spanner可以将嵌套的数据放在一起,这样在分区的时候性能会提升很多。否则Spanner 无法获知最重要的表之间的关系。

 

TrueTime

TrueTime API 是一个非常有创意的东西,可以同步全球的时间。上表就是TrueTime APITT.now()可以获得一个绝对时间TTinterval,这个值和UnixTime是相同的,同时还能够得到一个误差e。 TT.after(t)TT.before(t)是基于TT.now()实现的。

那这个TrueTime API实现靠的是GFS和原子钟。之所以要用两种技术来处理,是因为导致这两个技术的失败的原因是不同的。GPS会有一个天线,电波干扰会导致其失灵。原子钟很稳定。当GPS失灵的时候,原子钟仍然能保证在相当长的时间内,不会出现偏差。

实际部署的时候。每个数据中心需要部署一些Master机器,其他机器上需要有一个slave进程来从Master同步。有的Master用 GPS,有的Master用原子钟。这些Master物理上分布的比较远,怕出现物理上的干扰。比如如果放在一个机架上,机架被人碰倒了,就全宕了。另外 原子钟不是并很贵。Master自己还会不断比对,新的时间信息还会和Master自身时钟的比对,会排除掉偏差比较大的,并获得一个保守的结果。最终 GPS master提供时间精确度很高,误差接近于0

每个Slave后台进程会每个30秒从若干个Master更新自己的时钟。为了降低误差,使用Marzullo算法。每个slave还会计算出自己的误差。这里的误差包括的通信的延迟,机器的负载。如果不能访问Master,误差就会越走越大,知道重新可以访问。

 

Google Spanner并发控制

Spanner使用TrueTime来控制并发,实现外部一致性。支持以下几种事务。

·        读写事务

·        只读事务

·        快照读,客户端提供时间戳

·        快照读,客户端提供时间范围

例如一个读写事务发生在时间t,那么在全世界任何一个地方,指定t快照读都可以读到写入的值。

上表是Spanner现在支持的事务。单独的写操作都被实现为读写事务 ; 单独的非快照被实现为只读事务。事务总有失败的时候,如果失败,对于这两种操作会自己重试,无需应用自己实现重试循环。

时间戳的设计大大提高了只读事务的性能。事务开始的时候,要声明这个事务里没有写操作,只读事务可不是一个简单的没有写操作的读写事务。它会用一个 系统时间戳去读,所以对于同时的其他的写操作是没有Block的。而且只读事务可以在任意一台已经更新过的replica上面读。

对于快照读操作,可以读取以前的数据,需要客户端指定一个时间戳或者一个时间范围。Spanner会找到一个已经充分更新好的replica上读取。

还有一个有趣的特性的是,对于只读事务,如果执行到一半,该replica出现了错误。客户端没有必要在本地缓存刚刚读过的时间,因为是根据时间戳读取的。只要再用刚刚的时间戳读取,就可以获得一样的结果。

 

读写事务

正如BigTable一样,Spanner的事务是会将所有的写操作先缓存起来,在Commit的时候一次提交。这样的话,就读不出在同一个事务中写的数据了。不过这没有关系,因为Spanner的数据都是有版本的。

在读写事务中使用wound-wait算法来避免死锁。当客户端发起一个读写事务的时候,首先是读操作,他先找到相关数据的leader replica,然后加上读锁,读取最近的数据。在客户端事务存活的时候会不断的向leader发心跳,防止超时。当客户端完成了所有的读操作,并且缓存 了所有的写操作,就开始了两阶段提交。客户端闲置一个coordinator group,并给每一个leader发送coordinatorid和缓存的写数据。

leader首先会上一个写锁,他要找一个比现有事务晚的时间戳。通过Paxos记录。每一个相关的都要给coordinator发送他自己准备的那个时间戳。

Coordinatorleader一开始也会上个写锁,当大家发送时间戳给他之后,他就选择一个提交时间戳。这个提交的时间戳,必须比刚刚的所有时间戳晚,而且还要比TT.now()+误差时间 还有晚。这个Coordinator将这个信息记录到Paxos

在让replica写入数据生效之前,coordinator还有再等一会。需要等两倍时间误差。这段时间也刚好让Paxos来同步。因为等待之 后,在任意机器上发起的下一个事务的开始时间,都比如不会比这个事务的结束时间早了。然后coordinator将提交时间戳发送给客户端还有其他的 replica。他们记录日志,写入生效,释放锁。

 

只读事务

对于只读事务,Spanner首先要指定一个读事务时间戳。还需要了解在这个读操作中,需要访问的所有的读的KeySpanner可以自动确定Key的范围。

如果Key的范围在一个Paxos group内。客户端可以发起一个只读请求给group leaderleader选一个时间戳,这个时间戳要比上一个事务的结束时间要大。然后读取相应的数据。这个事务可以满足外部一致性,读出的结果是最后 一次写的结果,并且不会有不一致的数据。

如果Key的范围在多个Paxos group内,就相对复杂一些。其中一个比较复杂的例子是,可以遍历所有的group leaders,寻找最近的事务发生的时间,并读取。客户端只要时间戳在TT.now().latest之后就可以满足要求了。 

 

参考文献:

1、《挑战传统关系型数据库:FaceBook图形数据库TAO揭秘》 Jordan Novet

2、《云时代的分布式数据库:阿里分布式数据库服务DRDS》 沈询

3、《大数据与云计算》李永红

4、《基于云计算的数据库分析》 谢红 

5、《全球级的分布式数据库Google Spanner原理》

你可能感兴趣的:(数据库)