第1章 概述
当前是数据库世界的一个重要时刻。多年来,无论针对的问题是大还是小,关系模型一直是事实上的选择。我们不指望关系数据库会很快消失,但是人们正在从RDBMS的迷雾中走出来,寻找替代的方案,如无模式或可替代的数据结构,可简单复制,具有高可用性,可横向扩展,以及新的查询方法。这些选择统称为NoSQL,而NoSQL占据了本书的大部分内容。
本书将探讨七种数据库,涉及各种数据库风格。在阅读本书的过程中,你将了解每个数据库具有的各种功能和折中,如持久性与速度、绝对一致性与最终一致性等,并学会如何针对你的使用场景,做出最好的决策。
1.1 从一个问题开始
本书的核心问题是:哪种数据库或数据库组合最好地解决了你的问题?读完本书,如果你知道如何根据特定需求和手头的资源做出这种选择,我们会很高兴。
但要回答这个问题,你需要了解你的选择。为此,我们将带你深入这7个数据库,揭示精华,并指出瑕疵。你将亲手尝试CRUD操作,发挥你使用的模式的力量,并找到下面这些问题的答案:
●这是什么类型的数据库?数据库分为各种类型,例如,关系型、键-值型、多列型、面向文档型和图型。流行的数据库(包括本书中介绍的)一般可以划分为这几大类型。你将了解每种类型的数据库,以及它们最适合的各种问题。我们对本书涉及的数据库精心挑选,以覆盖这些类型,包括一个关系数据库(Postgres),两个键-值存储数据库(Riak 和Redis),一个面向列的数据库(HBase),两个面向文档的数据库(MongoDB和CouchDB),以及一个图数据库(Neo4j)。
●驱动力是什么?数据库不是凭空产生的。它们是为了解决实际使用中提出的问题。在 RDBMS(关系数据库管理系统)出现的环境中,数据库查询的灵活性比灵活的模式更重要。另一方面,建立面向列的数据库是为了适于存储跨多机的大量数据,而数据之间的关系退居次要地位。我们将介绍使用每个数据库的场景和相关的例子。
●如何与数据库交互?数据库往往支持多种连接选项。只要某个数据库有交互式的命令行界面,我们会首先使用它,之后再介绍其他方法。如果需要编程,我们主要使用Ruby和JavaScript,尽管不时会用到其他几种语言,如PL/pgSQL(Postgres)和Gremlin(Neo4j)。更深入一层,我们将讨论诸如REST(CouchDB和Riak)和Thrift(HBase)协议。第9章将介绍一个更复杂的数据库环境,它由Node.js JavaScript实现联接在一起。
●每种数据库的独特性体现在哪里?任何数据存储库都支持写入和读回数据。它们在其他的方面彼此大不相同。有些数据库允许对任意字段的查询。有些数据库提供快速索引查找。有些数据库支持自由定义的查询(ad hoc query);而其他的数据库的查询必须先规划。模式是数据库所强制的一个刚性框架,或仅仅是一些随意商定的准则?理解每种数据库的功能和限制,将有助于挑选适合你的工作的数据库。
●每种数据库的性能如何?这个数据库如何工作?其开销如何?它支持分片吗?复制呢?它是否使用一致散列均匀地分布数据?它将相似的数据放在一起吗?这个数据库为读、写或其他操作做了优化吗?如果你能对优化进行控制,程度如何?
●每种数据库的可伸缩性如何?可伸缩性与性能相关。没有上下文,谈论可伸缩性一般不会有结论。本书会提供背景知识,你在建立这个上下文时就能提出正确的问题。虽然如何扩展每个数据库的讨论会有意淡化,但在这些章节里,你会发现每种数据存储库是更容易实现横向扩展(MongoDB、Hbase 和 Riak),还是传统的纵向扩展(Postgres、Neo4j和Redis),或者介于两者之间。
我们的目标不是将某种数据库的新手培养成大师。如果这样做的话,其中任何一个数据库都将充满整本书的篇幅。但最终你应该能够牢牢把握每个数据库的优势,以及它们的不同。
1.2 风格
如同音乐一样,各种数据库有着其本身独特的风格。所有的歌曲都使用同样的音符,但是有些音符对某些网络的歌曲更合适。少有人驾驶着敞篷车,沿着 405 号公路超速行驶,同时播放巴赫的《B小调弥撒曲》。同样,在某些情况下,一些数据库比其他数据库更好些。你要问的不是“我能够用这个数据库来存储和完善数据吗?”而是“我应该用这个数据库吗?”
本节将要探讨 5种主要的数据库类型,也会简单介绍每种类型中我们要关注的数据库。
重要的是要记住,你将面临的大多数数据问题,可以用本书中的大部分或全部数据库解决,更别说还有其他数据库。问题不是某种数据库风格是否能别生搬硬套地用来为你的数据建模,而是它是否最适合你的问题领域、使用模式,以及可用的资源。你将学会预测一种数据库是否在本质上对你有用,而这是一门艺术。
1.2.1 关系数据库
关系模型通常是大多数有数据库经验的人首先想到的。关系数据库管理系统(Relational DataBase Management System,RDBMS)是以集合理论为基础的系统,实现为具有行和列的二维表。与RDBMS交互的标准方法,是用结构化查询语言(Structured Query Language,SQL)编写查询。数据值具有类型,可以是数字、字符串、日期、未解释的二进制大对象,或其他类型。系统强制使用类型。重要的是,表可以联接并转化为新的、更复杂的表,因为它们的数学基础是关系(集合)理论。
有许多开源关系数据库可供选择,包括MySQL、H2、HSQLDB、SQLite等。第2章将介绍PostgreSQL。
PostgreSQL
PostgreSQL久经沙场,它是迄今为止我们介绍的最古老和最健壮的数据库。PostgreSQL符合SQL标准,之前曾使用过关系数据库的人都会觉得熟悉它,这为我们将使用的其他数据库提供了一个坚实的比较基础。我们还将探讨一些不大为人熟悉的 SQL 功能以及Postgres特有的优势。从SQL新手到专家,每个人都能从中有所收获。
1.2.2 键-值数据库
键-值(Key-Value,KV)存储库是我们介绍的最简单的模型。顾名思义,KV存储库将键与值配对,类似于所有流行编程语言中的映射(或哈希表)。某些KV实现允许复杂的值类型,如哈希或列表,但这不是必需的。一些 KV 实现提供了一种迭代遍历键的方式,但这也是额外的好处。如果你将文件的路径视为键而将文件内容作为值,文件系统也可以看成是键-值存储库。因为KV存储库对资源的要求非常少,所以这种数据库类型在一些场景中有令人难以置信的高性能,但是当你有复杂的查询和聚合需求时,它一般不会有帮助。
与关系数据库一样,有许多开源的 KV 存储库可以选择。一些较受欢迎的产品包括memcached(及相关的memcachedb和membase)、Voldemort,以及我们在本书中介绍的两个产品:Redis和Riak。
1.Riak
第3章介绍的Riak不仅仅是一个键-值存储库,它从一开始就支持HTTP和REST等Web方式。它严格实现了亚马逊Dynamo的原理,具有一些高级功能,如解决冲突的向量时钟。Riak中的值可以是任何内容,从纯文本到XML到图像数据,而键之间的关系由称为链接(link)的命名结构处理。Riak是本书中知名度较小的数据库,但它越来越受欢迎,在我们将要讨论的数据库中,它是第一个通过mapreduce支持高级查询的数据库。
2.Redis
Redis提供复杂的数据类型,如有序集合和哈希,以及基本消息模式,如发布-订阅和阻塞队列。它是查询机制最健壮的KV存储库之一。在写入磁盘之前先写入内存缓存, Redis 因此获得了惊人的性能,代价是在出现硬件故障的情况下,增加了数据丢失的风险。这一特性使得它适合用于缓存非关键数据,或作为消息代理。我们将它留到最后介绍(参见第8章),以便可以用Redis与其他数据库配合,构建多数据库应用。
1.2.3 列型数据库
列型(或面向列的数据库)的命名源自于其设计的一个重要方面,即来自一个给定的列(在二维表的意义上)的数据存放在一起。相比之下,面向行的数据库(如RDBMS),将一行的信息保存在一起。这种差异看起来似乎无关紧要,但实际上这种设计决策的影响很深。在面向列的数据库中,添加列是相当简易的,而且是逐行完成的。每一行可以有一组不同的列,或完全没有,允许表保持稀疏(sparse),而不会产生空值的存储成本。在结构方面,列型数据库大约介于关系数据库和键-值存储库之间。
在列型数据库市场中,竞争相比关系数据库或键-值存储较少。三种最流行的产品是HBase(在第4章中介绍)、Cassandra和Hypertable。
HBase
在我们介绍的所有非关系数据库中,这个面向列的数据库与关系模型最为相似。以Google的BigTable论文作为蓝图,HBase建立在Hadoop(一个mapreduce引擎)之上,其设计目标是在常用硬件的集群上横向伸缩。HBase 保证了强一致性并提供带行和列的表的功能,这使得SQL粉丝有宾至如归的感觉。它直接支持版本控制和压缩,这令它在“大数据”的世界中与众不同。
1.2.4 文档型数据库
当然,面向文档的数据库存储的就是文档。简而言之,文档就像是哈希,具有一个独一无二的标识符(ID)字段和值,值可能是任何类型,包括更多的哈希。文档可以包含嵌套的结构,因此,它们表现出了高度的灵活性,允许有可变域。该系统对输入的数据很少有限制,只要它满足基本要求,可以表示为一个文档。在建索引、自由定义的查询、复制、一致性及其他设计决策等方面,不同的文档数据库采取了不同的方法。需要了解这些差异,及其对特定使用场景的影响,才能在它们之间做出明智地选择。
文档数据库市场中的两大开源产品是MongoDB(在第5章中介绍)和CouchDB(在第6章中介绍)。
1.MongoDB
MongoDB的设计目标是支持巨大的数据(名字mongo是从单词humongous中提取的)。Mongo服务器的配置试图保持一致性:如果你写入了什么内容,随后的读取将得到相同的值(直到下次更新)。这一特性吸引了那些具有RDBMS背景的人。它也提供了一些原子读写操作(如递增一个值),以及对嵌套文档结构的深层查询。MongoDB 利用 JavaScript 作为查询语言,支持简单的查询和复杂的mapreduce工作。
2.CouchDB
CouchDB 的目标是各种部署场景,从数据中心到桌面,一直到智能手机。CouchDB是用Erlang编写的,具有独特的坚固性,这一点在大部分其他数据库中是缺乏的。由于它的数据文件几乎不可摧毁,即使是面对间歇性的连接丢失或硬件故障,CouchDB也仍能保持高可用性。像Mongo一样,CouchDB的原生查询语言是JavaScript。视图包括mapreduce函数,它们以文档的形式存储并在节点之间复制,像任何其他的数据一样。
1.2.5 图数据库
这是一种不太常用的数据库类型,图数据库善于处理高度互联的数据。图数据库包含节点及节点之间的关系。节点和关系可以有一些属性(一些键-值对),用来存储数据。图数据库的真正实力是按照关系遍历节点。
第7章讨论现在最流行的图数据库Neo4j。
Neo4j
在遍历自我引用或以其他方式杂乱地连接在一起的数据时,其他数据库常常操作失败。这正是Neo4j使人眼前一亮的地方。使用图数据库的好处在于能够快速在节点和关系之间移动,找到相关数据。图数据库经常用在社交网络应用中,它们因灵活性而受到关注,Neo4j是其中的佼佼者。
1.2.6 混合使用多种数据库
在实际环境中,各种数据库经常一起使用。使用单一的关系数据库仍然很常见,但随着时间的推移,流行的做法是同时使用几种数据库,利用它们各自的长处,创建一个生态系统,比其各部分的功能总和更强大、更全面、更健壮。这种做法叫做多持久并存(Polyglot Persistence),第9章将进一步讨论这一主题。
1.3 前进和提升
我们正处在数据存储选择的寒武纪大爆炸之中,很难准确预测未来会如何发展。但我们可以相当肯定,任何一种特定策略(关系型或其他类型)都不大可能大获全胜。相反,我们将看到越来越多的专用数据库,每种适合一组特定(但肯定有重叠)的理想问题。今天有一些工作需要关系数据库的专业知识(DBA),同样,我们会看到对应的非关系领域的增长。
与编程语言和程序库一样,数据库是另一套工具,每个开发人员都应该知道数据库。每一个好木匠必须了解他的工具箱里有什么。就像所有好的建筑师一样,如果你不熟悉可供你使用的多种选择,就不会成为一名大师。
本书就像是一个车间里的速成课。在本书中,你会挥动锤子,转动电钻,使用射钉枪,并最终能够建立比鸟笼子更大、更复杂的东西。闲话少说,我们来使用我们的第一个数据库:PostgreSQL。