一文带你了解什么是 NoSQL

1,790 阅读22分钟

什么是 NoSQL?

NoSQL实际上是两个词的组合:No和SQL。这意味着NoSQL是一种对抗SQL的技术或产品。

流行语NoSQL的创造者和早期采用者可能想说No RDBMS或No Relations,但迷恋于听起来更好的NoSQL并坚持下去。

在适当的时候,一些人提出了NonRel作为NoSQL的替代品.其他一些人试图通过提出NoSQL实际上是一个扩展到“not only SQL”的首字母缩略词来挽救原始术语。

无论字面意思如何,NoSQL今天被用作所有数据库和数据存储的总称,这些数据库和数据存储不遵循流行和完善的RDBMS原则,并且通常与在Web规模上访问和操作的大型数据集有关。这意味着NoSQL不是一个单一的产品,甚至不是一个单一的技术。它代表了一类产品和有关数据存储和操作的各种(有时是相关的)概念的集合。

背景和一些历史

在我开始详细介绍NoSQL类型和所涉及的概念之前,设置NoSQL出现的上下文非常重要。非关系数据库并不新鲜。事实上,第一个非关系存储可以追溯到第一套计算机被发明的时候。非关系数据库因大型机的出现而蓬勃发展,并存在于专用和特定领域 - 例如,用于存储身份验证和授权凭据

出现在NoSQL世界中的是一个新的化身,它诞生于可大规模扩展的Internet应用程序的世界。这些非关系型NoSQL存储在很大程度上是在分布式和并行计算领域构思的。

从Inktomi开始,它可以被认为是第一个真正的搜索引擎,到谷歌,很明显,广泛采用的关系数据库管理系统(RDBMS)在应用于大量数据时有其自身的一系列问题。这些问题与高效处理、有效并行化、可扩展性和成本有关。

RDBM的挑战

RDBMS在大规模Web级数据处理方面的挑战并非特定于产品,而是与此类数据库的整个类别有关。

RDBMS假设数据中有一个定义明确的结构。它假定数据是密集的,并且在很大程度上是均匀的。RDBMS建立在可以预先定义数据属性的先决条件之上,并且其相互关系已建立并系统地引用。它还假定可以在数据集上一致地定义索引,并且可以统一利用此类索引来加快查询速度。

不幸的是,一旦这些假设不成立,RDBMS就会开始显示出让位的迹象。RDBMS当然可以处理一些不规则和缺乏结构的问题,但在具有松散定义的结构的大量稀疏数据集的背景下,RDBMS似乎是一种强制拟合。对于海量数据集,典型的存储机制和访问方法也会捉襟见肘。非规范化表、删除约束和放宽事务保证可以帮助RDBMS扩展,但是在这些修改之后,RDBMS开始类似于NoSQL产品。

灵活性是有代价的:

NoSQL缓解了RDBMS带来的问题,使处理大型稀疏数据变得容易,但反过来又剥夺了事务完整性和灵活的索引和查询的力量。

具有讽刺意味的是,NoSQL中最缺少的功能之一是SQL,该领域的产品供应商正在进行各种尝试来弥合这一差距。

在过去的几年里,谷歌已经为其搜索引擎和其他应用程序构建了一个大规模可扩展的基础设施,包括谷歌地图、谷歌地球、GMail、谷歌财经和谷歌应用。

谷歌的方法是在应用程序堆栈的每个级别解决问题。目标是构建一个可扩展的基础架构,用于并行处理大量数据。因此,Google创建了一个完整的机制,其中包括分布式文件系统,面向列系列的数据存储,分布式协调系统和基于MapReduce的并行算法执行环境。

非常客气的是,谷歌发表并提交了一系列论文,解释了其基础设施的一些关键部分。

谷歌向公众发布的论文激发了开发人员的极大兴趣。

开源搜索引擎的创建者Lucene是第一个开发开源版本的人,该版本复制了Google基础架构的某些功能。随后,Lucene的核心开发人员加入了雅虎,在许多其他贡献者的帮助下,他们创建了一个平行宇宙,模仿了谷歌分布式计算堆栈的所有部分。这个开源替代方案是Hadoop,它的子项目,以及它的相关项目。

在没有进入Hadoop开发的确切时间表的情况下,在其第一个版本中出现了NoSQL的想法。

谁创造了NoSQL这个术语的历史以及何时创造是无关紧要的,但重要的是要注意,Hadoop的出现为NoSQL的快速增长奠定了基础。此外,重要的是要考虑到谷歌的成功有助于推动新时代分布式计算概念,Hadoop项目和NoSQL的健康采用。在谷歌的论文激发了人们对并行可扩展处理和非关系分布式数据存储的兴趣一年后,亚马逊决定分享自己的一些成功故事。

2007年,亚马逊提出了一个名为Dynamo的分布式高度可用和最终一致的数据存储的想法。

随着两大网络巨头谷歌和亚马逊对NoSQL的认可,这一领域出现了几款新产品。许多开发人员开始考虑在他们的应用程序中使用这些方法的想法,许多企业,从初创公司到大公司,都愿意更多地了解这项技术,并可能使用这些方法。在不到5年的时间里,NoSQL和管理大数据的相关概念已经变得普遍,许多知名公司都出现了用例,包括Facebook,Netflix,Yahoo,eBay,Hulu,IBM等等。其中许多公司还通过向世界开源其扩展和新产品做出了贡献。


你很快就会学到很多关于各种NoSQL产品的知识,包括它们的异同,

但是,现在让我离题,简要介绍一下围绕大数据和并行处理的一些挑战和解决方案。这个弯路将帮助所有读者在开始探索NoSQL产品时做好准备。

大数据

究竟有多少数据才算是大数据?

这个问题必然会征求不同的回答,这取决于你问谁。答案也可能因提问时间而异。目前,任何超过几TB的数据集都被归类为大数据。这通常是数据集足够大以开始跨越多个存储单元的大小。这也是传统RDBMS技术开始显示出压力最初迹象的规模。

字节是由 8 位组成的数字信息单位。在国际单位制 (SI) 方案中,每 1,000 (103) 个字节的倍数被赋予一个不同的名称,如下所示:

1Byte = 8 Bit

1 KB = 1,024 Bytes 

1 MB = 1,024 KB = 1,048,576 Bytes 

1 GB = 1,024 MB = 1,048,576 KB = 1,073,741,824 Bytes

1 TB = 1,024 GB = 1,048,576 MB = 1,073,741,824 KB = 1,099,511,627,776 Bytes

1 PB = 1,024 TB = 1,048,576 GB =1,125,899,906,842,624 Bytes

1 EB = 1,024 PB = 1,048,576 TB = 1,152,921,504,606,846,976 Bytes

1 ZB = 1,024 EB = 1,180,591,620,717,411,303,424 Bytes

1 YB = 1,024 ZB = 1,208,925,819,614,629,174,706,176 Bytes

即使在几年前,TB的个人数据可能看起来也相当大。但是,现在本地硬盘驱动器和备份驱动器通常以这种大小提供。在接下来的几年里,如果您的默认硬盘驱动器容量超过几TB,也就不足为奇了。我们生活在一个数据增长迅猛的时代。我们的数码相机输出、博客、每日社交网络更新、推文、电子文档、扫描内容、音乐文件和视频正在快速增长。我们正在消耗大量数据并生成它。

很难评估数字化数据的真实大小或互联网的大小,但一些研究、估计和数据点表明,它非常大,在一项正在进行的名为“数字宇宙十年 - 你准备好了吗? 的报告中。该报告声称,到2020年,创建和复制的数字数据的总大小将增长到35泽字节。该报告还声称,现在产生和可用的数据量正在超过可用存储量。

其他一些值得考虑的数据点如下:

  • 2009年发表在ACM上的一篇论文,题为“MapReduce:简化的大型数据处理”集群———透露谷歌每天处理24PB的数据。

  • 2009年,Facebook关于其照片存储系统的一篇文章“大海捞针:数十亿张照片的有效存储”--提到Facebook中照片的总大小为1.5佩字节。同一篇文章提到,Facebook上存储了大约600亿张图片。

  • archive.org 的互联网档案馆常见问题解答说,互联网档案馆中存储了2PB的数据。它还说数据正在以每月 20 TB 的速度增长。

  • 电影《阿凡达》占用了1PB的存储空间用于渲染3D CGI效果。(“信不信由你:阿凡达占用 1 PB 的存储空间,相当于 32 年的 MP3”-- 空间相当于 32 年长的 mp3)。

随着数据规模的增长和数据创建来源的日益多样化,以下不断增长的挑战将进一步放大:

  • 有效地存储和访问大量数据是困难的。容错和备份的额外需求使事情变得更加复杂。

  • 操作大型数据集涉及运行非常并行的进程。在此类运行期间从任何故障中正常恢复并在合理的短时间内提供结果非常复杂。

  • 管理由不同来源生成的半结构化和非结构化数据的不断发展的架构和元数据是一个复杂的问题。

因此,存储和检索大量数据的方式和方法需要超越我们当前方法的新方法。NoSQL和相关大数据解决方案是朝着这个方向迈出的第一步。

可扩展性

可伸缩性是系统通过添加资源来解决负载增加问题来提高吞吐量的能力。

可扩展性可以通过预配大型而强大的资源来满足额外需求来实现,也可以通过依赖普通计算机集群作为一个单元来实现。大型、功能强大的机器的参与通常被归类为垂直可扩展性。配置具有许多 CPU 内核和大量直连存储的超级计算机是典型的垂直扩展解决方案。这种垂直缩放选项通常既昂贵又专有。垂直可伸缩性的替代方法是水平可伸缩性。水平可伸缩性涉及商用系统集群,其中集群随着负载的增加而扩展。

水平可伸缩性通常涉及添加其他节点以提供额外的负载。

大数据的出现以及对大规模并行处理来操纵这些数据的需求导致了水平可扩展基础设施的广泛采用。谷歌、亚马逊、Facebook、eBay和雅虎的一些水平扩展基础设施涉及大量服务器。其中一些基础设施有数千甚至数十万台服务器。

处理分布在水平扩展计算机群集中的数据非常复杂。

MapReduce模型可能提供了在水平机器集群上处理大规模数据的最佳方法之一。

定义和介绍

MapReduce是一种并行编程模型,允许对计算机集群上的大型数据集进行分布式处理。MapReduce框架已获得专利,但这些想法在许多开源实现中被自由分享和采用.

MapReduce的想法和灵感来自函数式编程领域的概念。

map和reduce是函数式编程世界中常用的函数。

在函数式编程中,map 函数将操作或函数应用于列表中的每个元素。

例如,列表 [1, 2, 3, 4] 上的乘以 2 函数将生成另一个列表,如下所示:

[2, 4, 6, 8]

应用此类函数时,不会更改原始列表。函数式编程相信保持数据不可变,避免在多个进程或线程之间共享数据。这意味着刚刚说明的map函数,尽管它可能微不足道,可以通过列表中的两个或多个多个线程运行,并且这些线程不会相互踩踏,因为列表本身不会改变。

与map函数一样,函数式编程具有reduce函数的概念。实际上,函数式编程中的reduce函数通常被称为折叠函数。减少或折叠函数有时也称为累加、压缩或注入函数。缩减或折叠函数将函数应用于数据结构的所有元素(如列表),并生成单个结果或输出。因此,对映射函数生成的列表(即 [2,4,6,8])应用类似 reduce 函数的求和将生成等于 20 的输出。

因此,map和reduce函数可以结合使用来处理数据列表,其中函数首先应用于列表的每个成员,然后将聚合函数应用于转换和生成的列表。

映射和归约的简单想法已扩展到大型数据集。这个想法被稍微修改为处理元组或键/值对的集合。map 函数对集合中的每个键/值对应用一个函数,并生成一个新集合。然后,reduce函数处理新生成的集合,并应用聚合函数来计算最终输出。通过一个例子可以更好地理解这一点,所以让我举一个微不足道的例子来解释流程。假设您有一个键/值对的集合,如下所示:

[{ “94303”: “Tom”}, {“94303”: “Jane”}, (“94301”: “Arun”}, {“94302”:“Chen”}]

这是键/值对的集合,其中键是邮政编码,值是居住在该邮政编码内的人员的姓名。此集合上的简单地图函数可以获取居住在特定邮政编码中的所有人的姓名。此类映射函数的输出如下:

[{"94303":["Tom", "Jane"]},{"94301":["Arun"]},{"94302":["Chen"]}]

现在,reduce函数可以在此输出上工作,以简单地计算属于特定邮政编码的人数。最终输出如下:

[("94303": 2},("94301": 1},{"94302": 1)]

这个例子非常简单,MapReduce机制对于这样的操作来说似乎太复杂了,但我希望你能理解概念和流程背后的核心思想。

排序的有序列存储

谷歌的Bigtable支持一种模型,其中数据以面向列的方式存储。这与RDBMS中的面向行的格式形成鲜明对比。面向列的存储允许有效地存储数据。当该列不存在值时,只需不存储该列,从而避免在存储 null 时占用空间。

每个数据单元都可以被认为是一组键/值对,其中单元本身是借助主标识符(通常称为主键)来标识的。Bigtable 及其克隆倾向于将此主键称为行键。此外,单位以有序排序的方式存储。数据单元根据行键进行排序和排序。为了解释排序的有序面向列的存储,示例比大量文本更好,因此让我向您介绍一个例子。考虑一个简单的值表,它保留有关一组人员的信息。此类表可以包含first_name、last_name、occupotion、zip_code和gender等列。此表中的人员信息可能如下所示:

first_name:John 
last_name:Doe 
zip_code:10001 
gender:male

同一表中的另一组数据可能如下所示:

first_name:Jane
zip_code:94303

第一个数据点的行键可以是 1,第二个数据点可以是 2。然后,数据将存储在排序的有序列式存储中,行键为 1 的数据点将存储在具有行键 2 的数据点之前,并且两个数据点将彼此相邻。接下来,将只为每个数据点存储有效的键/值对。所以,该示例可能的一个列系列可以是具有列first_name的名称,last_name是其成员。另一个列族可以是以 zip_code 作为其成员的位置。第三个列系列可以是profile。gender列可以是个人资料的成员列族。在类似于 Bigtable 的面向列的存储中,数据以列系列为基础存储。列族通常在配置或启动时定义。列本身不需要先验定义或声明。此外,列能够存储任何数据类型,只要数据可以持久化为字节数组。

因此,这个简单示例的基础逻辑存储由三个存储桶组成:名称、位置和配置文件。在每个存储桶中,仅存储具有有效值的键/值对。因此,名称列系列存储桶存储以下值:

For row-key:1 
first_name:John
last_name:Doe

For row-key:2 
first_name:Jane

location列系列存储以下内容:

zip_code:10001 
For row-key:2 
zip_code:94303

profile列系列仅具有行键为 1 的数据点的值,因此它仅存储以下内容:

For row-key:1 
gender:male

在实际存储术语中,列族对于给定行不是物理隔离的。与行键相关的所有数据都存储在一起。列系列充当其包含的列的键,行键充当整个数据集的键。

Bigtable 及其克隆中的数据以连续的顺序方式存储。随着数据增长以填满一个节点,它被分散到多个节点中。数据不仅在每个节点上进行排序和排序,而且跨节点进行排序和排序,提供一个大型连续排序集。数据以容错方式持久保存,其中维护每个数据集的三个副本。大多数 Bigtable 克隆利用分布式文件系统将数据持久保存到磁盘。分布式文件系统允许数据存储在计算机集群中。

排序有序结构使按行键查找数据非常高效。数据访问不是随机和临时的,查找就像在保存数据的序列中查找节点一样简单。数据将插入到列表的末尾。更新是就地更新的,但通常意味着将较新版本的数据添加到特定单元,而不是就地覆盖。这意味着始终维护每个单元的几个版本。版本控制属性通常是可配置的。

HBase是一个流行的,开源的,排序的有序列系列存储,以Google的Bigtable提出的想法为蓝本。

存储在HBase中的数据可以使用MapReduce基础设施进行操作。Hadoop的MapReduce工具可以很容易地使用HBase作为数据源和/或接收器。

键/值存储

哈希映射或关联数组是最简单的数据结构,可以保存一组键/值对。这样的数据结构非常流行,因为它们为访问数据提供了非常有效的大O(1)平均算法运行时间。键/值对的键是集合中的唯一值,可以轻松查找以访问数据。

键/值对有多种类型:有些将数据保存在内存中,有些提供将数据保存到磁盘的功能。键/值对可以分布并保存在节点集群中。

一个简单但功能强大的键/值存储是Oracle的Berkeley DB。Berkeley DB 是一个纯存储引擎,其中键和值都是一个字节数组。Berkeley DB 的核心存储引擎不会将意义附加到键或值上。它接受字节数组对并将其返回给调用用户。

Berkeley DB 允许将数据缓存在内存中,并随着数据的增长刷新到磁盘。还有一个概念是索引键以加快查找和访问速度。伯克利DB自1990年代中期以来一直存在。它的创建是为了取代AT&T的NDBM,作为从BSD 4.3迁移到1996 4.4.In 的一部分,Sleepycat软件的成立是为了维护和提供对Berkeley DB的支持。

另一种常用的键/值存储类型是缓存。缓存提供应用程序中最常用的数据的内存中快照。缓存的目的是减少磁盘 I/O。缓存系统可以是基本的映射结构,也可以是具有缓存过期策略的健壮系统。缓存是一种流行的策略,用于计算机软件堆栈的所有级别,以提高性能。操作系统、数据库、中间件组件和应用程序使用缓存。

健壮的开源分布式缓存系统,如EHCache广泛用于Java应用程序。EHCache可以被认为是NoSQL解决方案。另一个在 Web 应用程序中广泛使用的缓存系统是 Memcached,它是一个开源的高性能对象缓存系统。Brad Fitzpatrick在2003年为LiveJournal创建了Memcached。除了作为缓存系统之外,Memcached 还通过创建大型虚拟池并根据需要在节点之间分配内存来帮助有效的内存管理。这可以防止碎片区域,其中一个节点可能具有多余但未使用的内存,而另一个节点可能缺少内存。

随着NoSQL运动的势头越来越强,出现了许多键/值对数据存储。其中一些较新的存储基于Memcached API构建,一些使用Berkeley DB作为底层存储,还有一些其他商店提供从头开始构建的替代解决方案。

其中许多键/值对都具有允许获取和设置机制来获取和设置值的 API。一些,如Redis,提供了更丰富的抽象和强大的API。Redis 可以被视为数据结构服务器,因为它除了映射之外,还提供字符串(字符序列)、列表和集合等数据结构。此外,Redis 还提供了一组非常丰富的操作来访问来自这些不同类型的数据结构的数据。

这里列出的三个键/值对是灵活、快速的实现,为实时数据、临时常用数据甚至全面持久性提供存储。

到目前为止列出的键/值对为其存储的数据提供了强大的一致性模型。但是,其他一些键/值对强调分布式部署中的可用性而不是一致性。其中许多灵感来自亚马逊的Dynamo,这也是一个键/值对。亚马逊的Dynamo承诺了卓越的可用性和可扩展性,并构成了亚马逊分布式容错和高可用性系统的骨干。Apache Cassandra,Basho Riak和Voldemort是Amazon Dynamo提出的想法的开源实现。

Amazon Dynamo 将许多关键的高可用性理念带到了最前沿。最重要的想法是最终的一致性。最终一致性意味着,当数据在对等节点之间更新时,复制节点之间可能存在很小的不一致间隔。

最终一致性并不意味着不一致。它只是意味着一种比RDBMS中典型的ACID类型一致性更弱的一致性形式。

所有三个Cassandra,Riak和Voldemort都提供开源的Amazon Dynamo功能。

Cassandra和Riak在他们的行为和属性方面表现出双重性质。

Cassandra拥有Google Bigtable和Amazon Dynamo的属性。

Riak 既充当键/值存储,又充当文档数据库。

文档数据库

文档数据库不是文档管理系统。通常情况下,从NoSQL开始的开发人员会将文档数据库与文档和内容管理系统混淆。文档数据库中的word文档表示文档中结构松散的键/值对集,通常是JSON(JavaScript对象表示法),而不是文档或涂抹酱(尽管这些也可以存储)。

文档数据库将文档视为一个整体,避免将文档拆分为其组成名称/值对。在集合级别,这允许将一组不同的文档组合到单个集合中。文档数据库不仅允许根据其主要标识,还允许根据其属性对文档编制索引。

目前有几种不同的开源文档数据库可用,但可用选项中最突出的是MongoDB和CouchDB。


本文正在参加「技术专题19期 漫谈数据库技术」活动