NoSQL介绍[转载]

这是一篇关于NoSQL的入门文章,转载于此

本文目录

 

一 引言:NoSQL兴起的背景

曾几何时,金融,电信,MIS,ERP等软件类型占据了整个软件业的大半江山。那个时候,程序员的工作中有相当大一部分是与事务,增删改查,ODBC,JDBC或者Hibernate这种框架相关;架构师们总在考虑的也都是建表,拆表,建索引,行级锁,页级锁等等问题。那个时候,很多准备入行的新手都把目光瞄准到了ORACLE,INFORMIX等大型数据库的DBA上,因为关系数据库技术已经发展得相对成熟,新技术的更新速度并不像软件开发领域那样迅速,所以一旦成长为优秀的DBA,就可以较长时间地站在行业领域的顶端,而且并不需要太多持续的成本投入,这在某种程度上几乎成为了IT业的意识形态。

然而,随着web2.0时代的来临,随着我们的系统所必须存储,处理的数据量快速增长,奋战在第一线的架构师和DBA们开始越来越多地感觉到了传统关系数据库解决方案的力不从心,越来越多的高并发读写常常让MYSQL,ORACLE崩溃;越来越多的数据以无法预计的速度暴涨,导致没完没了的拆表,扩容;越来越多的社区网站出现了,但却因为数据库无法支撑而频频阻塞用户响应,很快又消失了。这一切都来得那么快,让数据库专家们束手无策,好像以前的“好日子”一去不返了。

就在这时,一个新名词越来越多地出现在各大技术论坛,博客和期刊上,那就是NoSQL。

这是一个一旦出现需求,马上就会有实现的时代。NoSQL天生就是为解决上述问题而产生的。现在,当我们随便打开一个NoSQL数据库的主页,无论是MongoDB,Cassandra,Memcachedb,或者别的什么,你基本都会看到这样的关键词:scalable,high performance,scheme-less。对比一下上面我们所遇到的问题,这不恰恰就是我们所要的东西么。

相对于传统的RDBMS关注事务,ACID,关联等需求所作出的复杂设计,NoSQL数据库针对性更强。scalable,可以平滑增加系统存储能力,解决数据量暴涨带来的拆表等问题;high performance,通过数据的分布式存储等特性带来对抗高读写压力的能力,可以解决高并发问题;scheme less可以让使用者更加灵活地修改数据库中的数据结构,更优雅地应付需求变更,另外web2.0网站应用中很多数据只存储在单表,基本不需要关联,这也符合NoSQL的使用原则。既然如此,那么时下如此多的NoSQL数据库纷纷崛起也就是顺理成章的事了。

NoSQL的出现引发了很多争论,甚至引起了一些人的抵触,这是可以理解的。不过我想现在NoSQL和SQL之间的关系很像几年以前OOP与AOP的关系,当时很多熟悉OOP的程序员都感觉到了不小压力,觉得一种全新的编程模式出现了,而且正要取代自己所熟悉的。其实事实证明二者之间并无竞争关系,相反却是很好的补充,它们相安无事地运行在系统的不同方面,一起让我们的程序变得更优雅,更健壮。现在,NoSQL 也同样并不需要,而且也没有能力取代关系数据库,他们将分别服务于不同场景,为架构师们,DBA们提供更全面,更好的解决方案。

当时间已经来到2010年秋天,虽然并没有一个正式的里程碑,但我们必须承认NoSQL已经乘着开源软件的浪潮,正式站到数据存储历史的舞台上了。

二 NoSQL的分类

1、世界上每件事物都会有很多面,NoSQL当然也是。我们可以根据NoSQL的很多特性来分类,比如实现语言,针对CAP理论的实现策略等等。但我个人更愿意按照http://nosql-database.org/ 中所列出的前三种来分类:

(1) 面向列(列族):
常见的一般都实现自Google的论文《Bigtable: A Distributed Storage System for Structured Data 》,扩展性好,面向列存储,适合存储大量结构化,半结构化数据。
代表:HBase,Cassandra,HyperTable。
(2) 面向文档:
常见的一般以JSON等文档格式存储组织数据。没有scheme,比较灵活。
代表:MongoDB,CouchDB。
(3) key/value
结构最简单,存取性能最高,但是适用场景比较单一,适合存储简单的key/value对。
代表:MemcacheDB,Tokyo Cabinet/Tyrant。

2、CAP theorem

CAP是Consistency, Availability, Partition Tolerance的缩写。CAP theorem是指在一个分 布式系统中,无法同时满足C,A,P三种特性,只能选取其中两种来实现。CAP理论是设计分布式系统的公理,同时也可以作为选取分布式数据库的高层依据,因为接下来的介绍中经常会涉及到CAP,所以在这里先做一下简单介绍。关于CAP的详细信息可以参考:http://en.wikipedia.org/wiki/CAP_theorem 以及 http://www.julianbrowne.com/article/viewer/brewers-cap-theorem

三 常见NoSQL数据库以及它们的特性

1:HBase

a、因为HBase的体系结构几乎完全是继承自Google的BigTable,所以可以说是常见的NoSQL中最为复杂的,这可以体现在几点上:

(1) HBase的存储是基于HDFS(apache HADOOP子项目的分布式文件系统)的,这表示HBase的每次读操作都需要通过HDFS层来取得数据,这也在一定程度上决定了HBase的随机读性能是比较低的。
(2) 不像Cassandra等平等的NoSQL数据库,HBase集群中的节点是分为Master和RegionServer的。其中Master负责Region的分配,而RegionServer负责存储Regions数据(在HBase中,数据严格按照key的字母顺序排序,并且分为不同的区块,叫做Region,一个Region在Metadata表中以startrow和endrow来确定)。这在一定程度上也为HBase引入了单点问题(虽然client端的读写并不依赖于Master)。
(3) 整个框架是通过一套叫做ZooKeeper的程序来协调控制cluster内的各个节点的(对应BigTable的Chubby)。
(4) 以上三点涉及到的HDFS,Master,RegionServer,Zookeeper,都有各自的配置文件,且可配置项繁多,这也使得HBase的安装部署比较繁琐。
HBase存储结构
图1:HBase存储结构

b、HBase的面向列(列族)特性。

(1) HBase说起来是面向列,其实是按照cell存储的,确定一个cell的key是由row key,version,column family, column name几项组成的。由于HBase是按照key的字母顺序紧凑排列cells,所以scan效率非常高(对应于b-tree存储结构)。
(2) HBase的存储文件格式叫做hfile。而在一个Region中不同列族的数据是存储在不同的hfile中的。所以,如果一次数据访问过程中只访问某个column family的数据,效率会更高。这也使得设计table scheme时的column family定义更加重要。

c、Hbase的读写流程大概是这样:

(1) client依次访问Zookeeper,ROOT Table, Metadata Table,得到需要处理的row所在Region,并缓存该信息在本地。
(2) Client直接连接该RegionServer。
(3) 若写,则直接写在RegionServer中的memstore,并且记录日志。待memstore已满,框架则自动flush内存数据到HDFS中的hfile中。因为写操作直接面对memstore,所以效率很高。
(4) 若读,则直接寻找Region对应的hfiles(因为每次内存flush都会生成新的hfile,所以读操作可能会寻找多个hfile文件,这也是HBase随机读效率较低的原因之一)。

d、Hbase选取CAP中的C和A来实现,因此对Partition Tolerance的支持不好。不过这对于所有节点都放在同一个机房的集群来说不是什么大问题。另外,其实HBase并没有数据库层面的replication机制,而完全是由HDFS中与生俱来的replication机制来完成的。

e、因为HBase的数据分为多个Region,而且HBase本身就基于HADOOP,所以HBase中存储的数据天然地支持map/reduce计算模式。这为HBase作为数据仓库存储提供了可能。

f、HBase中数据的顺序存储带来了hot spot问题。在用户集中大量访问某个范围的数据时,举个例子来说,访问某个域名下的网页内容,由于数据库中的key按照字母数序排序,那么同一域名下的页面内容也就都存在一个或者几个相邻的Region中,那么这些Regions所在的RegionServer压力将会明显增大,而这时其他服务器可能压力很小,从而形成了负载不均衡的情况。

g、HBase用java实现。

h、HBase扩展性良好。

综上,HBase的scan性能和random write性能都还是不错的,但是随机读性能要差一些,扩展性良好,可以很好地支持m/r。尤其适用于快速大量地写入数据,但读时要求不很高,且要求分布式数据处理的数据分析系统。比如BigTable在Google Analytics的应用模式,我想大概就是这样(当然BigTable的读性能和HBase还是不可同日而语的)。

read heavy情况下几种数据库read性能对比
图2:read heavy情况下几种数据库read性能对比 (测试结果来自Yahoo!)
read heavy情况下几种数据库write性能对比
图3:read heavy情况下几种数据库write性能对比(测试结果来自Yahoo!)
几种数据库scan性能比较
图4:几种数据库scan性能比较(测试结果来自Yahoo!)

2:MongoDB

引用:
a MongoDB bridges the gap between key-value stores (which are fast and highly scalable) and traditional RDBMS systems (which provide rich queries and deep functionality).
MongoDB (from “humongous”) is a scalable, high-performance, open source, document-oriented database.
–mongodb.org

a、从上面这段简介可以看出MongoDB的志向所在,以及大概的特点。

(1) 处理“超大”数据。
(2) 面向文档(JSON),结构灵活,scheme-less。
(3) 填补key/value数据库和关系数据库之间的缺口,寻找高性能存取和丰富的查询功能之间的平衡。如图5所示,MongoDB要达到的目标就是基本等同于,或者略低于key/value数据库的性能(远远高于RDBMS),但是却比key/value数据库丰富很多的查询功能。
MongoDB与key/value数据库,RDBMS的对比
图5:MongoDB与key/value数据库,RDBMS的对比

b、因为MongoDB基本支持了所有的关系数据库常用功能,比如按任意列查询(对比key/value数据库只能按照key查询),排序,索引等等,是由关系数据库过度到NoSQL的最好选择。
c、Replication。

(1) Replication是MongoDB提供的复制机制,用作数据冗余和错误恢复。用户可以在程序中控制write和read操作,从而控制一致性的程度。
(2) Replication目前(1.6)包括Master/Slave以及Replica Set两种方案。其中Replica Set是从1.6版本刚刚可用的,它支持自动错误恢复,但是并没有经过大规模集群测试,有些风险;Master/Slave方案久经考验,但节点出现错误需要手动配置解决。具体资料可参考:http://www.mongodb.org/display/DOCS/Master+Slave
MongoDB的Replication方案
图6:MongoDB的Replication方案

d、Sharding。

(1) MongoDB的sharding功能支持水平扩展,平滑实现扩容。
(2) 限制:未经大规模测试,一些功能还不支持(如db.eval())。
(3) 数据按照某种预定义的顺序分布在各个不同shards server中存储,每个shard server中包含多个chunk(很像HBase中的region,同样顺序存储相邻的数据)用来存储真正的数据,这和HBase的分布式结构类似。client的request传递给mongos,后者将请求route到某个或某些shards,整合结果再返回。其中mongos通过启动时从config server得到的metadata定位存储数据的shard server和chunk。config server的作用有点像hbase中的Metadata表。
(4) MongoDB的sharding是表级别的,不是数据库级别的,即可以设定数据库中的某些表为sharding的,某些表不是,依旧存储在一台服务器。
(5) MongoDB的shards是平等的,没有master的概念,每个shards可以包含n个replication。集群中可以有多个config server和mongos。如图7所示:
MongoDB servers layout

图7:MongoDB servers layout

e、GridFS。这是一个非常有用的特性,相当于一个分布式文件系统,可以存储大文件,比如图片,视频等。框架会将每个大文件的metedata存入file collection,实际文件内容分为多个部分存在chunk collection中。我觉得这个特性如果成熟,很适合快速存取邮件附件。
f、Capped collections。这是一种固定大小,速度非常快的表。它利用LRU算法丢掉某些旧的documents,进而插入新的documents,非常适合记录固定日期的日志,或者LRU缓存等 等。
g、map/reduce。MongoDB支持map/reduce,其中map/redude函数用JavaScript来实现。
h、MongoDB使用c++开发。
i、MongoDB不支持事务,joins。
j、MongoDB的安装,部署非常简单。

3:MemcacheDB
a、MemcacheDB是一个成熟的key/value分布式数据库。是很多key/value数据库中的杰出代表。
b、不要被MemecacheDB的名字所迷惑,它和著名的Memcached的应用模式完全不同,MemcacheDB完全是永久存储方案。

引用:
A complete memcached, but
*NOT* a cache solution –《memcachedb guide》

c、MemcacheDB支持事务,但不支持更多关系数据库功能。
d、和其他key/value数据库相似,MemcacheDB比其他种类NoSQL(当然也包括SQL)性能更高。
e、MemcacheDB的API接口和Memcached兼容。
f、MemcacheDB底层基于BerkeleyDB。
g、Replication:

(1) MongoDB通过底层BerkeleyDB的Replication机制来实现复制。
(2) BerkeleyDB的Replication采取Master/Slaves模式。
(3) 与mongo类似,MemcacheDB同样支持通过设置ack类型来控制Consistency的程度。其中ack类型包括ACKS_ALL,ACKS_NONE,ACKS_ALL_PEER,ACKS_ONE_PEER,ACKS_QUORUM等。它们分别描述了Master必须等待几个replication node复制确认,与Mongo的getLastError对应。

四 根据应用场景选取NoSQL

作为技术人员,经常关注和研究新技术,跟踪技术热点是很好的习惯。但是当我们为产品选择技术时,无论一项技术有多么流行,有多么吸引人,最关键的还是它是否适合我们的系统,我们的系统是否需要它。如果我们要做一个事务密集,需要大量关联表的产品,那么虽然TT/MemcachedDB能给我们提供很高的读取速度,HT/HBase能给我们带来Map/Reduce的能力和良好的扩展性,CouchDB/MongoDB可以自由改变数据存储结构,但是我们还是要老老实实选择MYSQL或者Oracle,因为它们能契合最关键的需求,即使可能我们要继续忍受拆表的痛苦。

对一项技术的需求可能涵盖很多方面。普遍的范畴下有诸如稳定性,性能,文档是否齐全,支持是否完备等等;针对NoSQL来说,我想最主要的是对CAP模型的需求。

拿性能需求举例来说,它还可以分为read性能,write性能,scan性能。再细分还可以分为分别在write heavy和read heavy环境下的read性能,write性能,scan性能,以及random read,random write,sequence read等。可见我们需要对备选技术做详细的研究和测试之后,或者从其他途径获取这些指标之后才可以做出准确的判断。但是NoSQL市场上有如此多产品,要一一做到这些实在是要花费大量人力和时间成本的。

我们只能先根据一些更为抽象,宏观,或者粒度更大的指标做出筛选,然后再对筛选出的结果做更细的工作。

依旧拿常见的一些NoSQL产品举例:

  • 如果需要存储结构化或者半结构化的数据,且希望得到比较好的并发读写性能,又不严格要求一致性,那么Cassandra是一个很好的选择。
  • 如果需要存储,处理海量数据,并且生成数据统计分析报表一类的输出(即表示对read并发性能要求不是那么高),或者主要访问模式为scan ,那么非常适合HADOOP+HBASE。这里的统计分析的情况还可以考虑HIVE。HIVE是Apache下的一个开源项目,它的目标是数据仓库,本质是HADOOP的客户端,定义了自己的一套查询语言(类似于SQL),可以把简单的查询语句编译成为map/reduce任务加以执行。
  • 如果想得到接近于key/value数据库的高性能,又希望为client提供动态查询能力,则MongoDB是最好选择。另外,如果希望从MYSQL迁移到NoSQL以获得更好的扩展能力和更高的性能,MongoDB也非常适合(同样因为它的动态查询能力可以涵盖大多数关系数据库查询操作)。
  • 如果需要存储海量key/value对(且尺寸不是很大),那么Tokyo Tyrant/MemcacheDB类型的数据库是不错的选择。

分布式系统的开发和实现是非常困难的,需要解决很多难题。现在有如此多的NoSQL产品,从宏观来看,它们可以提供给我们比较统一的接口,但是解决那些难题的技术细节则被很好地封装了起来,如果我们要真正了解NoSQL,那些隐藏起来的技术实现是重要的。本篇文章也并没有包含太多细节,只是我对NoSQL技术的一些粗浅理解,目的仅仅是向不太了解这项技术的同事们做一个概要介绍,算是抛砖引玉了吧。正如文章开头所提到的,现代计算机系统所处理的数据正越来越大,所要求的读写性能越来越高,NoSQL是顺应潮流的,而且目前仅仅出于起步阶段,我相信它的未来一定会越来越好。

由于本人水平有限,如有错误,请大家指正!

参考资料: