您当前的位置: 首页 >  mongodb

phymat.nico

暂无认证

  • 0浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

关于Mongodb的全面总结

phymat.nico 发布时间:2018-01-01 03:57:05 ,浏览量:0

MongoDB的内部构造《MongoDB The Definitive Guide》

MongoDB的官方文档基本是how to do的介绍,而关于how it worked却少之又少,本人也刚买了《MongoDB TheDefinitive Guide》的影印版,还没来得及看,本文原作者将其书中一些关于MongoDB内部现实方面的一些知识介绍如下,值得一看。

今天下载了《MongoDB The Definitive Guide》电子版,浏览了里面的内容,还是挺丰富的。是官网文档实际应用方面的一个补充。和官方文档类似,介绍MongoDB的内部原理是少之又少,只有在附录的一个章节中介绍了相关内容。

对于大多数的MongoDB的用户来说,MongoDB就像是一个大黑盒,但是如果你能够了解到MongoDB内部一些构造的话,将有利于你更好地理解和使用MongoDB。

BSON

在MongoDB中,文档是对数据的抽象,它被使用在Client端和Server端的交互中。所有的Client端(各种语言的Driver)都会使用这种抽象,它的表现形式就是我们常说的BSON(Binary JSON )。

BSON是一个轻量级的二进制数据格式。MongoDB能够使用BSON,并将BSON作为数据的存储存放在磁盘中。

当Client端要将写入文档,使用查询等等操作时,需要将文档编码为BSON格式,然后再发送给Server端。同样,Server端的返回结果也是编码为BSON格式再放回给Client端的。

使用BSON格式出于以下3种目的:

效率

BSON是为效率而设计的,它只需要使用很少的空间。即使在最坏的情况下,BSON格式也比JSON格式再最好的情况下存储效率高。

传输性

在某些情况下,BSON会牺牲额外的空间让数据的传输更加方便。比如,字符串的传输的前缀会标识字符串的长度,而不是在字符串的末尾打上结束的标记。这样的传输形式有利于MongoDB修改传输的数据。

性能

最后,BSON格式的编码和解码都是非常快速的。它使用了C风格的数据表现形式,这样在各种语言中都可以高效地使用。

更多关于BSON的介绍,可以参考:http://www.bsonspec.org。

写入协议

Client端访问Server端使用了轻量级的TCP/IP写入协议。这种协议在MongoDB Wiki中有详细介绍,它其实是在BSON数据上面做了一层简单的包装。比如说,写入数据的命令中包含了1个20字节的消息头(由消息的长度和写入命令标识组成),需要写入的Collection名称和需要写入的数据。

数据文件

在MongoDB的数据文件夹中(默认路径是/data/db)由构成数据库的所有文件。每一个数据库都包含一个.ns文件和一些数据文件,其中数据文件会随着数据量的增加而变多。所以如果有一个数据库名字叫做foo,那么构成foo这个数据库的文件就会由foo.ns,foo.0,foo.1,foo.2等等组成。

数据文件每新增一次,大小都会是上一个数据文件的2倍,每个数据文件最大2G。这样的设计有利于防止数据量较小的数据库浪费过多的空间,同时又能保证数据量较大的数据库有相应的空间使用。

MongoDB会使用预分配方式来保证写入性能的稳定(这种方式可以使用–noprealloc关闭)。预分配在后台进行,并且每个预分配的文件都用0进行填充。这会让MongoDB始终保持额外的空间和空余的数据文件,从而避免了数据增长过快而带来的分配磁盘空间引起的阻塞。

名字空间和盘区

每一个数据库都由多个名字空间组成,每一个名字空间存储了相应类型的数据。数据库中的每一个Collection都有各自对应的名字空间,索引文件同样也有名字空间。所有名字空间的元数据都存储在.ns文件中。

名字空间中的数据在磁盘中分为多个区间,这个叫做盘区。在下图中,foo这个数据库包含3个数据文件,第三个数据文件属于空的预分配文件。头两个数据文件被分为了相应的盘区对应不同的名字空间。

上图显示了名字空间和盘区的相关特点。每一个名字空间可以包含多个不同的盘区,这些盘区并不是连续的。与数据文件的增长相同,每一个名字空间对应的盘区大小的也是随着分配的次数不断增长的。这样做的目的是为了平衡名字空间浪费的空间与保持某一个名字空间中数据的连续性。上图中还有一个需要注意的名字空间:$freelist,这个名字空间用于记录不再使用的盘区(被删除的Collection或索引)。每当名字空间需要分配新的盘区的时候,都会先查看$freelist是否有大小合适的盘区可以使用。

内存映射存储引擎

MongoDB目前支持的存储引擎为内存映射引擎。当MongoDB启动的时候,会将所有的数据文件映射到内存中,然后操作系统会托管所有的磁盘操作。这种存储引擎有以下几种特点:

* MongoDB中关于内存管理的代码非常精简,毕竟相关的工作已经有操作系统进行托管。

* MongoDB服务器使用的虚拟内存将非常巨大,并将超过整个数据文件的大小。不用担心,操作系统会去处理这一切。

* MongoDB无法控制数据写入磁盘的顺序,这样将导致MongoDB无法实现writeahead日志的特性。所以,如果MongoDB希望提供一种durability的特性(这一特性可以参考我写的关于Cassandra文章:http://www.cnblogs.com/gpcuster/tag/Cassandra/),需要实现另外一种存储引擎。

* 32位系统的MongoDB服务器每一个Mongod实例只能使用2G的数据文件。这是由于地址指针只能支持32位。

其他

在《MongoDB The Definitive Guide》中介绍的MongoDB内部构造只有这么多,如果真要把它说清楚,可能需要另外一本书来专门讲述了。比如内部的JS解析,查询的优化,索引的建立等等。有兴趣的朋友可以直接参考源代码

 

 

MongoDB的架构

当前架构                           双服务器架构

 

 

 

 

 

 

 

 

 

 

 

 

 

当前架构为单shard+replica Set模式,双服务器为双Shard+Replica Set模式。同一个Shard中的primary和Secondary存储内容一致。而双Shard则是两个Shard分布式存储不同数据,备份由shard内部进行。

双服务器中的两个Shard各含一个primary ,一个secondary,和一个arbiter(arbiter的唯一作用是在primary 宕机后选举新的primary时拥有投票权,用以使存活节点数大于50%,不包括50%,否则系统将整个down掉,以及在票数相同的情况下用以打破选举的平衡,并不存储和读取数据)。

因为同一个shard中,只有primary可以用以写,secondary只是用于对primary节点的备份并用于读操作,然后再primary宕机的情况下接管它的工作。所以,双shard模式下,两个服务器分别包含一个primary,而且同一个shard的arbiter必须和secondary在一个服务器上。这样子既保证了两个服务器都可以进行读、写操作,而且在primary down的时候也能够继续使得选取成功secondary。

后续扩展时,可以再在集群中添加新的shard,然后与老的shard进行balance均衡操作。

MongoDB的特点

MongoDB 是一个面向集合的,模式自由的文档型数据库.

面向集合, 意思是数据被分组到若干集合,这些集合称作聚集(collections). 在数据库里每个聚集有一个唯一的名字,可以包含无限个文档. 聚集是RDBMS中表的同义词,区别是聚集不需要进行模式定义.

模式自由, 意思是数据库并不需要知道你将存入到聚集中的文档的任何结构信息.实际上,你可以在同一个聚集中存储不同结构的文档.

文档型, 意思是我们存储的数据是键-值对的集合,键是字符串,值可以是数据类型集合里的任意类型,包括数组和文档. 我们把这个数据格式称作 "[BSON]"即 "Binary Serialized dOcument Notation."

u  面向文档存储:(类JSON数据模式简单而强大)。

u  高效的传统存储方式:支持二进制数据及大型对象(如照片和视频)。

u  复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。

u  Auto-Sharding自动分片支持云级扩展性(处于早期alpha阶段):自动分片功能支持水平的数据库集群,可动态添加额外的机器。

u  动态查询:它支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。

u  全索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。

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

u  面向集合存储,易存储对象类型的数据:存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各中复杂的文件类型;

u  *模式自由:存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义;

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

u  *支持复制和故障恢复。

u  *自动处理碎片: 自动分片功能支持水平的数据库集群,可动态添加额外的机器

u 查询监视:Mongo包含一个监视工具用于分析数据库操作的性能

MongoDB的功能

       查询:基于查询对象或者类SQL语句搜索文档. 查询结果可以排序,进行返回大小限制,可以跳过部分结果集,也可以返回文档的一部分.

       插入和更新 : 插入新文档,更新已有文档.

       索引管理 : 对文档的一个或者多个键(包括子结构)创建索引,删除索引等等

常用命令: 所有MongoDB 操作都可以通过socket传输的DB命令来执行.

MongoDB的局限性与不足

本文来源于对Quora上一个问答的整理,主要列举了MongoDB身上一些局限的功能及目前做得不够好的地方。其中包括了原本就并非MongoDB想做的部分,也包括了MongoDB想做但没做好的方面。

  • 在32位系统上,不支持大于2.5G的数据。详见这里
  • 单个文档大小限制为 4 M/16 M(1.8版本后升为16M)
  • 锁粒度太粗,MongoDB使用的是一把全局的读写锁,详见这里
  • 不支持join操作和事务机制,这个确实是非MongoDB要做的领域
  • 对内存要求比较大,至少要保证热数据(索引,数据及系统其它开销)都能装进内存
  • 用户权限方面比较弱,这一点MongoDB官方推荐的是将机器部署在安全的内网环境中,尽量不要用权限,详见这里
  • MapReduce在单个实例上无法并行,只有采用Auto-Sharding才能并行。这是由JS引擎的限制造成的
  • MapReduce的结果无法写入到一个被Sharding的Collection中,2.0版本对这个问题的解决好像也不彻底
  • 对于数组型的数据操作不够丰富
  • Auto-Sharding还存在很多问题,所谓的水平扩展也不是那么理想
适用范围

u  适合实时的插入,更新与查询,并具备应用程序实时数据存储所需的复制及高度伸缩性。

u  适合作为信息基础设施的持久化缓存层。

u  适合由数十或数百台服务器组成的数据库。因为Mongo已经包含对MapReduce引擎的内置支持。

u  Mongo的BSON数据格式非常适合文档化格式的存储及查询。

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

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

u  ◆大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。

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

u  ◆用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储及查询

 

 

MongoDB的不适用范围

·        高度事务性的系统。

·        传统的商业智能应用。

·        级为复杂的SQL查询。

·        ◆高度事务性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。

·        ◆传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。

·        ◆需要SQL的问题

 

u   

要点

跟mysqld一样,一个mongod服务可以有建立多个数据库,每个数据库可以有多张表,这里的表名叫collection,每个collection可以存放多个文档(document),每个文档都以BSON(binary json)的形式存放于硬盘中。跟关系型数据库不一样的地方是,它是的以单文档为单位存储的,你可以任意给一个或一批文档新增或删除字段,而不会对其它文档造成影响,这就是所谓的schema-free,这也是文档型数据库最主要的优点。跟一般的key-value数据库不一样的是,它的value中存储了结构信息,所以你又可以像关系型数据库那样对某些域进行读写、统计等操作。可以说是兼备了key-value数据库的方便高效与关系型数据库的强大功能。

索引

跟关系型数据库类似,mongodb可以对某个字段建立索引,可以建立组合索引、唯一索引,也可以删除索引。当然建立索引就意味着增加空间开销,我的建议是,如果你能把一个文档作为一个对象的来考虑,在线上应用中,你通常只要对对象ID建立一个索引即可,根据ID取出对象某些数据放在memcache即可。如果是后台的分析需要,响应要求不高,查询非索引的字段即便直接扫表也费不了太多时间。如果还受不了,就再建一个索引得了。

默认情况下每个表都会有一个唯一索引:_id,如果插入数据时没有指定_id,服务会自动生成一个_id,为了充分利用已有索引,减少空间开销,最好是自己指定一个unique的key为_id,通常用对象的ID比较合适,比如商品的ID。

capped collection

capped collection是一种特殊的表,它的建表命令为:

db.createCollection("mycoll",{capped:true, size:100000})

允许在建表之初就指定一定的空间大小,接下来的插入操作会不断地按顺序APPEND数据在这个预分配好空间的文件中,如果已经超出空间大小,则回到文件头覆盖原来的数据继续插入。这种结构保证了插入和查询的高效性,它不允许删除单个记录,更新的也有限制:不能超过原有记录的大小。这种表效率很高,它适用于一些暂时保存数据的场合,比如网站中登录用户的session信息,又比如一些程序的监控日志,都是属于过了一定的时间就可以被覆盖的数据。

复制与分片

mongodb的复制架构跟mysql也很类似,除了包括master-slave构型和master-master构型之外,还有一个Replica pairs构型,这种构型在平常可以像master-slave那样工作,一但master出现问题,应用会自动了连接slave。要做复制也很简单,我自己使用过master-slave构型,只要在某一个服务启动时加上–master参数,而另一个服务加上–slave与–source参数,即可实现同步。

分片是个很头疼的问题,数据量大了肯定要分片,mysql下的分片正是成为无数DBA的噩梦。在mongodb下,文档数据库类似key-value数据库那样的易分布特性就显现出来了,无论构造分片服务,新增节点还是删除节点都非常容易实现。但mongodb在这方面做还不足够成熟,现在分片的工作还只做到alpha2版本(mongodb v1.1),估计还有很多问题要解决,所以只能期待,就不多说了。

性能

在我的使用场合下,千万级别的文档对象,近10G的数据,对有索引的ID的查询不会比mysql慢,而对非索引字段的查询,则是全面胜出。mysql实际无法胜任大数据量下任意字段的查询,而mongodb的查询性能实在让我惊讶。写入性能同样很令人满意,同样写入百万级别的数据,mongodb比我以前试用过的couchdb要快得多,基本10分钟以下可以解决。补上一句,观察过程中mongodb都远算不上是CPU杀手。

GridFS

gridfs是mongodb一个很有趣的类似文件系统的东西,它可以用一大块文件空间来存放大量的小文件,这个对于存储web2.0网站中常见的大量小文件(如大量的用户头像)特别有效。使用起来也很方便,基本上跟一般的文件系统类似。

用合适的数据库做适合的事情

mongodb的文档里提到的user case包括实时分析、logging、全文搜索,国内也有人使用mongodb来存储分析网站日志,但我认为mongodb用来处理有一定规模的网站日志其实并不合适,最主要的就是它占空间过于虚高,原来1G的日志数据它可以存成几个G,如此下去,一个硬盘也存不了几天的日志。另一方面,数据量大了肯定要考虑sharding,而mongodb的sharding到现在为止仍不太成熟。由于日志的不可更新性的,往往只需APPEND即可,又因为对日志的操作往往只集中于一两列,所以最合适作为日志分析的还是列存储型的数据库,特别是像infobright那样的为数据仓库而设计的列存储数据库。

由于mongodb不支持事务操作,所以事务要求严格的系统(如果银行系统)肯定不能用它。

MongoDB分布式复制

一、主从配置(Master Slave)     主从数据库需要两个数据库节点即可,一主一从(并不一定非得两台独立的服务器,可使用--dbpath参数指定数据库目录)。一个从节点可以有多个主节点,这种情况下,local.sources中会有多条配置信息。一台服务器可以同时即为主也为从。如果一台从节点与主节点不同步,比如从节点的数据更新远远跟不上主节点或者从节点中断之后重启但主节点中相关的数据更新日志却不可用了。这种情况下,复制操作将会终止,需要管理者的介入,看是否默认需要重启复制操作。管理者可以使用{resync:1} 命令重启复制操作,可选命令行参数 --autoresync可使从节点在不同步情况发生10秒钟之后,自动重启复制操作。如果指定了--autoresync参数,从节点在10分钟以内自动重新同步数据的操作只会执行一次。 --oplogSize命令行参数(与--master一同使用)配置用于存储给从节点可用的更新信息占用的磁盘空间(M为单位),如果不指定这个参数,默认大小为当前可用磁盘空间的5%(64位机器最小值为1G,32位机器为50M)。     二、互为主从(Replica Pairs)     数据库自动协调某个时间点上的主从关系。开始的时候,数据库会判断哪个是从哪个是主,一旦主服务器负载过高,另一台就会自动成为主服务器。 remoteserver组中的其他服务器host,可加:port指定端口。 arbiterserver 仲裁(arbiter )的host,也可指定端口。仲裁是一台mongodb服务器,用于协助判断某个时间点上的数据库主从关系。如果同组服务器在同一个交换机或相同的ec2可用区域内,就没必要使用仲裁了。如果同组服务器之间不能通信,可是使用运行在第三方机器上的仲裁,使用“抢七”方式有效地敲定主服务器,也可不使用仲裁,这样所有的服务器都假定是主服务器状态,可通过命令人工检测当前哪台数据库是主数据库: $ ./mongo  > db.$cmd.findOne({ismaster:1}); { "ismaster" : 0.0 , "remote" : "192.168.58.1:30001" , "ok" : 1.0 }  一致性:故障转移机制只能够保障组中的数据库上的数据的最终一致性。如果机器L是主服务器,然后挂了,那么发生在它身上的最后几秒钟的操作信息就到达不了机器R,那么机器R在机器L恢复之前是不能执行这些操作的。 安全性:同主从的操作相同。 数据库服务器替换。当一台服务器失败了,系统能自动在线恢复。但当一台机器彻底挂了,就需要替换机器,而替换机器一开始是没有数据的,怎么办?以下会解释如何替换一组服务器中的一台机器。

MongoDB语法与现有关系型数据库SQL语法比较

MongoDB语法                                  MySql语法

db.test.find({'name':'foobar'}) select * from test where name='foobar'

db.test.find()                            select *from test

db.test.find({'ID':10}).count() select count(*) from test where ID=10

db.test.find().skip(10).limit(20) select * from test limit 10,20

db.test.find({'ID':{$in:[25,35,45]}}) select * from test where ID in (25,35,45)

db.test.find().sort({'ID':-1})  select * from test order by IDdesc

db.test.distinct('name',{'ID':{$lt:20}})  select distinct(name) from testwhere ID use admin

> db.addUser("dba", "dbapassword")

完成之后,所有进一步的操作(甚至是该外壳程序中的操作)都需要经过身份验证,通过在该外壳程序中进行显式身份验证完成:

 

> db.authenticate("dba", "dbapassword")

DBA 现在可以更改数据库并使用前面所示的同一个addUser 调用来添加用户,从而将用户添加到MongoDB 数据库中:

 

> use mydatabase
> db.addUser("billg", "password")

通过Mongo.Driver 连接数据库时,身份验证信息将作为用于创建Mongo 对象的连接字符串的一部分进行传递,相同的身份验证过程将透明地进行:

 

var mongo = new Mongo("Username=billg;Password=password");

很自然,密码不应该直接硬编码在代码中或公开存储,而应该使用与所有基于数据库的应用程序相同的密码规则。实际上,整个配置(主机、端口、密码等)应该保存在配置文件中并通过ConfigurationManager 类进行检索。

扩展到另一些代码

管理员应该定期查看正在运行的实例,以获得正在运行的服务器的相关诊断信息。MongoDB支持一个 HTTP 接口用于与数据库交互,该接口运行的端口号比用于普通客户端通信的端口号高1,000。MongoDB 的默认端口是 27017,因此该 HTTP 接口位于端口 28017,如图 4 所示。

图 4 用于与 MongoDB 交互的HTTP 接口

该 HTTP 接口还允许更加偏向 REST 风格的通信方法,与MongoDB.Driver 和MongoDB.Linq 中的本机驱动程序正相反;MongoDB网站对此有详细介绍,但用于访问集合内容的HTTP URL 中需要添加数据库名称和集合名称(用斜线分隔),如图 5 所示。

图 5 用于访问集合内容的 HTTP URL

有关使用 WCF 创建 REST 客户端的详细信息,请参见 MSDN 文章“REST in WindowsCommunication Foundation (WCF)”。

专家的忠告

MongoDB 是一款发展迅速的产品,这些旨在探索MongoDB 核心功能的文章有很多内容并未涉猎。尽管MongoDB 不能直接替代SQL Server,但在传统的关系数据库管理系统作用有限的领域,它确实是一种可行的存储替代方案。与MongoDB 相同,mongodb-csharp项目也处在蓬勃发展之中。撰写本文时,很多新的改进功能已经添加到Beta 版中,包括使用普通对象处理强类型化的集合以及对LINQ 支持的重大改进。请密切注意这两个项目。

但现在我们也应该和MongoDB 说再见了。让我们把注意力转向孜孜不倦的程序员可能不熟悉(也应该存在争议)的其他开发人员领域。但在目前,愉快编程,并记住伟大的开发专家曾说过的“开发人员使用源代码获取知识,进行防御,切勿成为黑客”。

下载示例代码

关于作者:

Ted Neward 是 Neward & Associates 的负责人,这是一家专门研究 .NET Framework 企业系统和 Java 平台系统的独立公司。他曾写作 100 多篇文章,是 C# 领域最优秀的专家之一并且是 INETA 发言人,著作或合著过十几本书,包括即将出版的《Professional F# 2.0》(Wrox)。他定期担任顾问和导师,请通过 ted@tedneward.com 与他联系,或通过 blogs.tedneward.com 访问其博客。

 

MongoDB之父:MongoDB胜过BigTable

 

Dwight Merriman和他的团队,包括ShopWiki的创始人Eliot Horowitz参加了在纽约10gen启动MongoDB的仪式。现在该公司除了担任该开源项目的主要运营者之外,还提供支持、培训和咨询服务。10gen在旧金山举办了第二届开发者大会,Merriman在上午的大会做了主题演讲,主要介绍了MongoDB的起源,并解释了为何要建立这样的数据库。

“在2007年底,当时的想法是构建一个用于开发、托管并具有自动缩放Web应用程序的在线服务”,谈到MongoDB诞生之目的时,Merriman介绍道。“但是不同于Google App Engine的是,这项服务完全建立在一个开放源代码的软件平台之上。”因此,在关注了Google Bigtable架构很长一段时间后,Merriman和他的团队注意到,尚没有一个开源的数据库平台适合这种服务,这兴许是个机会。

“我们意识到很多现有的数据库并不真正具备‘云计算’的特性。例如弹性、可扩展性以及易管理性。这些特性能够为开发者和运营者带来便利,而MySQL还不完全具备这些特点。

因此,Dwight Merriman以及他的团队的目标是构建一个全新的数据库。新的数据库将会放弃大家所熟悉的关系数据库模型,且是适合现代网络应用并基于分布式的平台。高度事务性的系统可以帮助解决一些棘手的问题,同时还支持云计算架构的伸缩性。Merriman解释到。经过一年的不断努力,这个数据库已经比较完善。他们将它设计为具有为“云计算服务”潜力的数据库。而且还会不断的完善,因为MongoDB本身就是一个开源数据库。

在开源的、面向文档的数据库中,MongoDB经常被誉为具有RDBMS功能的NoSQL数据库。MongoDB还带有交互式shell,这使得访问其数据存储变得简单,且其对于分块的即装即用的支持能够使高可伸缩性跨多个节点。

据悉,MongoDB的API是JSON对象和JavaScript函数的本地混合物。通过shell程序开发人员可与MongoDB进行交互,即允许命令行参数,或通过使用语言驱动程序来访问数据存储实例。这里不存在类JDBC驱动程序,这意味着开发人员不必处理ResultSet或PreparedStatement。

而速度是 MongoDB 的另外一个优势,主要是由于它处理写入的方式:它们存储在内存中,然后通过后台线程写入磁盘。

“由于用户不容易在大规模环境下作分布式的链接,并且在分布式环境下很难做快速的大规模部署,因此,用户需要一些辅助的东西”,Memmiman解释道。

最后他表示同样重要的是为了限制数据库的事务语义你可以使用分布式事务。但当你在1000台机器上运行时它不会那么快。例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。(李智/译)

 

 

MongoDB与CouchDB全方位对比

本文见于MongoDB官方网站,MongoDB与CouchDB很相似,他们都是文档型存储,数据存储格式都是JSON型的,都使用Javascript进行操作,都支持Map/Reduce。但是其实二者有着很多本质的区别,本文透过现象追寻本质,让你更好的理解MongoDB与CouchDB。

1.MVCC(Multiversionconcurrency control)

MongoDB与CouchDB的一大区别就是CouchDB是一个MVCC的系统,而MongoDB是一个update-in-place的系统。这二者的区别就是,MongoDB进行写操作时都是即时完成写操作,写操作成功则数据就写成功了,而CouchDB一个支持多版本控制的系统,此类系统通常支持多个结点写,而系统会检测到多个系统的写操作之间的冲突并以一定的算法规则予以解决。

2.水平扩展性

在扩展性方面,CouchDB使用replication去做,而MongoDB的replication仅仅用来增强数据的可靠性,MongoDB在实现水平扩展性方面使用的是Sharding。(据说CouchDB也有开发分片功能的计划)

3.数据查询操作

这个区别在用户接口上了,MongoDB与传统的数据库系统类似,支持动态查询,即使在没有建立索引的行上,也能进行任意的查询。而CouchDB不同,CouchDB不支持动态查询,你必须为你的每一个查询模式建立相应的view,并在此view的基础上进行查询。

4.原子性

这一点上两者比较一致,都支持针对行的原子性修改(concurrentmodifications of single documents),但不支持更多的复杂事务操作。

5.数据可靠性

CouchDB是一个”crash-only”的系统,你可以在任何时候停掉CouchDB并能保证数据的一致性。而MongoDB在不正常的停掉后需要运repairDatabase()命令来修复数据文件,在1.7.5版本后支持单机可靠的–dur命令。

6.Map/Reduce

MongoDB和CouchDB都支持Map/Reduce,不同的是MongoDB只有在数据统计操作中会用到,而CouchDB在变通查询时也是使用Map/Reduce。

7.使用 javascript

MongoDB和CouchDB都支持javascript,CouchDb用javascript来创建view。MongoDB使用JSON作为普通数据库操作的表达式。当然你也可以在操作中包含javascript语句。MongoDB还支持服务端的javascript脚本(running arbitrary javascript functions server-side),当然,MongoDB的Map/Reduce函数也是javascript格式的。

8.REST

CouchDB是一个RESTFul的数据库,其操作完全走HTTP协议,而MongoDB是走的自己的二进制协议。MongoDB Server在启动时可以开放一个HTTP的接口供状态监控。

9.性能

此处主要列举了MongoDB自己具有高性能的原因

采用二进制协议,而非CouchDB REST的HTTP协议

使用Momary Map内存映射的做法

collection-oriented,面向集合的存储,同一个collection的数据是连续存储的

update-in-place直接修改,而非使用MVCC的机制

使用C++编写

10.适用场景

如果你在构建一个 Lotus Notes型的应用,我们推荐使用CouchDB,主要是由于它的MVCC机制。另外如果我们需要master-master的架构,需要基于地理位置的数据分布,或者在数据结点可能不在线的情况下,我们推荐使用CouchDB。

如果你需要高性能的存储服务,那我们推荐MongoDB,比如用于存储大型网站的用户个人信息,比如用于构建在其它存储层之上的Cache层。

如果你的需求中有大量update操作,那么使用MongoDB吧。就像我们在例子updating real time analytics counters中的一样,对于那种经常变化的数据,比如浏览量,访问数之类的数据存储。

 

Mongodb GridFS 介绍

MongoDB GridFS 是MongoDB用于文件存储的模块,本文简单介绍了期用法。

mongodb GridFS 性能

性能, 网评还不错.

不过在生产环境中,国外有用于存储视频流的.

GridFS的一个优点是可以存储上百万的文件而无需担心扩容性.

通过同步复制,可以解决分布式文件的备份问题.

通过ARP-ping可以实现一个双机热备切换,类mysql的mysql master master replic

使用Nginx module

http://github.com/mdirolf/nginx-gridfs

这是gridfs的nginx module. 可以通过nginx直接访问读取mongo gridfs中的文件.

和nginx对应的mogilefs module类似.

优点: 由于直接通过nginx,速度是最快的.

缺点: 只能通过file_path来查找,目前不支持_id来查找.因此必须在file_path上

建立索引.

其他一些信息:

1.通过runcommand可以直接在mongodb端运行处理脚本. 比如像mapreduce,或者一

些需要读取数据然后进行处理的.

这些command则是使用javascript方式来编写的,很容易. 好处就是避免了数据在服

务端和客户端之间的读取和传输,

提高效率.

2. sharding

sharding在目前开发版中已经具备,但还不成熟. 但是可以自己实现sharding比较

好.因为目前的sharding还是比较硬性的.

3.灵活使用magic操作符和upsert,比如$inc,$all,$in 等等

 

MongoDB:下一代MySQL? MongoDB的特性
  • 简单的查询语句,没有Join操作
  • 文档型存储,其数据是用二进制的Json格式Bson存储的。其数据就像Ruby的hashes,或者Python的字典,或者PHP的数组
  • Sharding,MongoDB提供auto-sharding实现数据的扩展性
  • GridFS,MongoDB的提供的文件存储API
  • 数组索引,你可以对文档中的某个数组属性建立索引
  • MapReduce,可以用于进行复杂的统计和并行计算
  • 高性能,通过使用mmap和定时fsync的方法,避免了频繁IO,使其性能更高
MongoDB的优点
  • 高性能,速度非常快(如果你的内存足够的话)
  • 没有固定的表结构,不用为了修改表结构而进行数据迁移
  • 查询语言简单,容易上手
  • 使用Sharding实现水平扩展
  • 部署方便
使用MongoDB,你得记住以下几点:
  • MongoDB 假设你有大磁盘空间
  • MongoDB 假设你的内存也足够大于放下你的热数据
  • MongoDB 假设你是部署在64位系统上的(32位有2G的限制,试用还可以)
  • MongoDB 假设你的系统是little-endian的
  • MongoDB 假设你有多台机器(并不专注于单机可靠性)
  • MongoDB 假设你希望用安全换性能,同时允许你用性能换安全
MongoDB在下面领域不太擅长
  • 不太稳定,特别是auto-sharding目前还有很多问题
  • 不支持SQL,这意味着你很多通过SQL接口的工具不再适用
  • 持久化,MongoDB单机可靠性不太好,宕机可能丢失一段时间的数据
  • 相关文档比较少,新功能都有这个问题
  • 相关人才比较难找,这也是新功能的问题之一
MongoDB安全性初探

本文是一篇转载文章,文章主要介绍了MongoDB 安全性方面的知识,包括 MongoDB 安全配制、认证机制及认证的网络流程,也简单介绍了可能利用JavaScript引擎执行脚本攻击的可能。

MongoDB,这么火的玩意其实早就想好好研究一下了。之前一直没空仔细学学新的东西,总是感觉精力不足。这次趁着买了一本书,就零零散散地在VPS上搭建、测试、看实现代码。感觉也蛮有意思的一个数据库。虽然感觉它非常简单,尤其是看代码的时候更是感觉如此。但这不也是另一个KISS的典范么,还是简单但是实用的东西最能流行。

既然都看了其实现,也不能不产出点什么。正好多年没更新博文,就简单分析一下 MongoDB 的安全性,凑个数先。

默认配置的安全情况

在默认情况下,mongod是监听在0.0.0.0之上的。而任何客户端都可以直接连接27017,且没有认证。好处是,开发人员或dba可以即时上手,不用担心被一堆配置弄的心烦意乱。坏处是,显而易见,如果你直接在公网服务器上如此搭建MongoDB,那么所有人都可以直接访问并修改你的数据库数据了。

默认情况下,mongod也是没有管理员账户的。因此除非你在admin数据库中使用db.addUser()命令添加了管理员帐号,且使用–auth参数启动mongod,否则在数据库中任何人都可以无需认证执行所有命令。包括delete和shutdown。

此外,mongod还会默认监听28017端口,同样是绑定所有ip。这是一个mongod自带的web监控界面。从中可以获取到数据库当前连接、log、状态、运行系统等信息。如果你开启了–rest参数,甚至可以直接通过web界面查询数据,执行mongod命令。

我试着花了一个晚上扫描了国内一个B段,国外一个B段。结果是国外开了78个MongoDB,而国内有60台。其中我随意挑选了10台尝试连接,而只有一台机器加了管理员账户做了认证,其他则全都是不设防的城市。可见其问题还是比较严重的。

其实MongoDB本身有非常详细的安全配置准则,显然他也是想到了,然而他是将安全的任务推给用户去解决,这本身的策略就是偏向易用性的,对于安全性,则得靠边站了。

用户信息保存及认证过程

类似MySQL将系统用户信息保存在mysql.user表。MongoDB也将系统用户的username、pwd保存在admin.system.users集合中。其中pwd =md5(username + “:mongo:” + real_password)。这本身并没有什么问题。username和:mongo:相当于对原密码加了一个salt值,即使攻击者获取了数据库中保存的md5 hash,也没法简单的从彩虹表中查出原始密码。

我们再来看看MongoDB对客户端的认证交互是如何实现的。mongo client和server交互都是基于明文的,因此很容易被网络嗅探等方式抓取。这里我们使用数据库自带的mongosniff,可以直接dump出客户端和服务端的所有交互数据包:

[root@localhost bin]# ./mongosniff --source NET lo
sniffing 27017 
 
...//省略开头的数据包,直接看看认证流程。以下就是当用户输入db.auth(username, real_passwd)后发生的交互。
 
127.0.0.1:34142  -->> 127.0.0.1:27017 admin.  62 bytes  id:8        8
        query: { getnonce: 1.0 }  ntoreturn: -1 ntoskip: 0
127.0.0.1:27017   127.0.0.1:27017 admin.  152 bytes  id:9       9
        query: { authenticate: 1.0, user: "admin", nonce: "df97182fb47bd6d0", key: "3d839522b547931057284b6e1cd3a567" }  ntoreturn: -1 ntoskip: 0
127.0.0.1:27017  db.blogposts.find( { "author.name" : "Jane" } )

>db.blogposts.findOne({ title : "My First Post","author.name": "Jane",   comments : [{ by: "Abe", text: "First" },              { by : "Ada", text : "Good post" } ] }) > db.blogposts.find( { "comments.by" : "Ada" } )

>db.blogposts.ensureIndex( { "comments.by" : 1 } ); 举例③: MongoDB是一个面向文档的数据库,目前由10gen开发并维护,它的功能丰富,齐全,完全可以替代MySQL。在使用MongoDB做产品原型的过程中,我们总结了MonogDB的一些亮点:   使用JSON风格语法,易于掌握和理解:MongoDB使用JSON的变种BSON作为内部存储的格式和语法。针对MongoDB的操作都使用JSON风格语法,客户端提交或接收的数据都使用JSON形式来展现。相对于SQL来说,更加直观,容易理解和掌握。   Schema-less,支持嵌入子文档:MongoDB是一个Schema-free的文档数据库。一个数据库可以有多个Collection,每个Collection是Documents的集合。Collection和Document和传统数据库的Table和Row并不对等。无需事先定义Collection,随时可以创建。   Collection中可以包含具有不同schema的文档记录。 这意味着,你上一条记录中的文档有3个属性,而下一条记录的文档可以有10个属性,属性的类型既可以是基本的数据类型(如数字、字符串、日期等),也可以是数组或者散列,甚至还可以是一个子文档(embeddocument)。这样,可以实现逆规范化(denormalizing)的数据模型,提高查询的速度。

图1 MongoDB是一个Schema-free的文档数据库

  图2是一个例子,作品和评论可以设计为一个collection,评论作为子文档内嵌在art的comments属性中,评论的回复则作为comment子文档的子文档内嵌于replies属性。按照这种设计模式,只需要按照作品id检索一次,即可获得所有相关的信息了。在MongoDB中,不强调一定对数据进行Normalize ,很多场合都建议De-normalize,开发人员可以扔掉传统关系数据库各种范式的限制,不需要把所有的实体都映射为一个Collection,只需定义最顶级的class。MongoDB的文档模型可以让我们很轻松就能将自己的Object映射到collection中实现存储。

图2 MongoDB支持嵌入子文档

③内置GridFS,支持大容量的存储。   GridFS是一个出色的分布式文件系统,可以支持海量的数据存储。   内置了GridFS了MongoDB,能够满足对大数据集的快速范围查询。 ④内置Sharding。 提供基于Range的Auto Sharding机制:一个collection可按照记录的范围,分成若干个段,切分到不同的Shard上。 Shards可以和复制结合,配合Replica sets能够实现Sharding+fail-over,不同的Shard之间可以负载均衡。查询是对客户端是透明的。客户端执行查询,统计,MapReduce等操作,这些会被MongoDB自动路由到后端的数据节点。这让我们关注于自己的业务,适当的时候可以无痛的升级。MongoDB的Sharding设计能力最大可支持约20 petabytes,足以支撑一般应用。 这可以保证MongoDB运行在便宜的PC服务器集群上。PC集群扩充起来非常方便并且成本很低,避免了“sharding”操作的复杂性和成本。

⑤第三方支持丰富。(这是与其他的NoSQL相比,MongoDB也具有的优势) 现在网络上的很多NoSQL开源数据库完全属于社区型的,没有官方支持,给使用者带来了很大的风险。 而开源文档数据库MongoDB背后有商业公司10gen为其提供供商业培训和支持。 而且MongoDB社区非常活跃,很多开发框架都迅速提供了对MongDB的支持。不少知名大公司和网站也在生产环境中使用MongoDB,越来越多的创新型企业转而使用MongoDB作为和Django,RoR来搭配的技术方案。 ⑥性能优越: 在使用场合下,千万级别的文档对象,近10G的数据,对有索引的ID的查询不会比mysql慢,而对非索引字段的查询,则是全面胜出。mysql实际无法胜任大数据量下任意字段的查询,而mongodb的查询性能实在让我惊讶。写入性能同样很令人满意,同样写入百万级别的数据,mongodb比我以前试用过的couchdb要快得多,基本10分钟以下可以解决。补上一句,观察过程中mongodb都远算不上是CPU杀手。

与关系型数据库相比,MongoDB的缺点: ①mongodb不支持事务操作。   所以事务要求严格的系统(如果银行系统)肯定不能用它。(这点和优点①是对应的) ②mongodb占用空间过大。   关于其原因,在官方的FAQ中,提到有如下几个方面: 1、空间的预分配:为避免形成过多的硬盘碎片,mongodb每次空间不足时都会申请生成一大块的硬盘空间,而且申请的量从64M、128M、256M那样的指数递增,直到2G为单个文件的最大体积。随着数据量的增加,你可以在其数据目录里看到这些整块生成容量不断递增的文件。

2、字段名所占用的空间:为了保持每个记录内的结构信息用于查询,mongodb需要把每个字段的key-value都以BSON的形式存储,如果value域相对于key域并不大,比如存放数值型的数据,则数据的overhead是最大的。一种减少空间占用的方法是把字段名尽量取短一些,这样占用空间就小了,但这就要求在易读性与空间占用上作为权衡了。我曾建议作者把字段名作个index,每个字段名用一个字节表示,这样就不用担心字段名取多长了。但作者的担忧也不无道理,这种索引方式需要每次查询得到结果后把索引值跟原值作一个替换,再发送到客户端,这个替换也是挺耗费时间的。现在的实现算是拿空间来换取时间吧。

3、删除记录不释放空间:这很容易理解,为避免记录删除后的数据的大规模挪动,原记录空间不删除,只标记“已删除”即可,以后还可以重复利用。

4、可以定期运行db.repairDatabase()来整理记录,但这个过程会比较缓慢

③MongoDB没有如MySQL那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方。

################################

Wordnik的MongoDB使用经验 http://news.cnblogs.com/n/80856/

视觉中国的NoSQL之路:从MySQL到MongoDB http://news.cnblogs.com/n/77959/

Wordnik的MongoDB使用经验

Wordnik是一项在线字典及百科全书服务,在大约一年前,它们逐渐开始从MySQL迁移至文档型数据库MongoDB,后者是著名的NoSQL产品之一。最近Wordnik的技术团队通过官方博客分享了这12个月来使用MongoDB经验及现状。

  据Wordnik技术团队描述,它们起初决定使用MongoDB,是看中了它的弱一致性(最终一致)及文档结构的存储方式。

  在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精确值。这在某些情况下,例如通过ATM查看账户信息的时候很重要,但对于Wordnik来说,数据是不断更新和增长的,这种“精确”的保证几乎没有任何意义,反而会产生很大的延迟。他们需要的是一个“大约”的数字已经更快的处理速度。

  此外,Worknik的数据结构是“层级”式的,如果要将这样的数据使用扁平式的,表状的结构来保存数据,这无论是在查询还是获取数据时都十分困难:

就拿一个“字典项”来说,虽然并不十分复杂,但还是会关系到“定义”、“词性”、“发音”或是“引用”等内容。大部分工程师会将这种模型使用关系型数据库中的主键和外键表现出来,但把它看作一个“文档”而不是“一系列有关系的表”岂不更好?使用“dictionary.definition.partOfSpeech='noun'”来查询也比表之间一系列复杂(往往代价也很高)的连接查询方便且快速。

  经过了一年的使用,Worknik描述了他们从MySQL全面迁移至MongoDB后的感受。

  首先是性能上的提高,这也是使用MongoDB的主要原因。MongoDB解决了Worknik在使用MySQL的时候,在存储和数据查询时都遇到的一些问题。下面是一些统计数据:

·     MongoDB承受了平均50万每小时的请求(包括周末和夜间),高峰期大约是4倍的量。

·     MongoDB中有超过120亿个文档。

·     每个节点大约3TB数据。

·     一般情况下文档插入速度为每条8千条,峰值为每秒5万条。

·     单个Java客户端在千兆带宽下,对单个MongoDB节点的可持续的传输速度为每秒10MB。同一个客户端的四个读取器可以保持每秒40MB的读取速度。

·     各种形式的查询都比MySQL的实现要快许多:

o  示例的获取速度,从400ms减少为60ms。

o  字典项获取速度,从20ms减少为1ms。

o  文档元数据的获取速度,从30ms减少为0.1ms。

o  拼写提示的获取速度,从10ms减少为1.2ms。

  Worknik表示,在压力较高的情况下,MongoDB的内置缓存机制,让系统对memcached层的每次调用节省了1-2ms,同时还剩下了许多GB的内存。此外,所有的数据不可能都在内存中,因此获取示例的60ms还包括磁盘访问时间。

  其次,使用MongoDB还带来了许多灵活性,除了之前提到的文档型存储让查询变得十分迅速之外,MongoDB还带来了其他一些好处。例如以前Worknik使用集群文件系统保存音频文件,如今这些文件保存在MongoDB的GridFS中。这给IT维护带来了许多方便,例如可以使用相同的方式来维护数据和文件内容,数据库和文件也是保持同步的。

  Worknik对MongoDB的可靠性也很满意,从四月起,MongoDB只重启了两次,一次是从1.4.2版升级到1.4.4版,还有一次是由于数据中心断电。

  唯一可能的抱怨是对于维护性上的。MongoDB没有如MySQL那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方。不过幸运的是,MongoDB提供了许多“接入点”,因此Worknit创建了一些辅助工具,并打算开源,他们表示将在十二月份的MongoSV上提供更多信息。

  在运营过程中,数据中心断电造成了很大的问题。由于断电发生在写密集的情况下,因此对主从节点都造成了损害。当时主节点正忙于将数据写回磁盘,而从节点正在通过日志获取数据。在电力回复之后,他们花费了超过24小时了来修复主节点上的数据,在这段时间内,他们将从节点提升为主节点使系统得以正常工作。

  最后,Worknik还分享了一些经验:

数据尺寸:在四月份的MongoSF会议上,我们曾抱怨MongoDB耗费了4倍的数据空间。之后10gen指出了MongoDB的集合填充机制,以及Worknik某些使用场景上造成的浪费。我们将一些对象作为子文档存储,并去除一些索引之后,则大约使用了MySQL的1.5至2倍的存储空间。

锁:某些情况下MongoDB会锁住数据库。如果此时正有数百个请求,则它们会堆积起来,造成许多问题。我们使用了下面的优化方式来避免锁定:

·        每次更新前,我们会先查询记录。查询操作会将对象放入内存,于是更新则会尽可能的迅速。在主/从部署方案中,从节点可以使用“-pretouch”参数运行,这也可以得到相同的效果。

·        使用多个mongod进程。我们根据访问模式将数据库拆分成多个进程。

  MongoDB是一个可扩展、高性能的下一代数据库。最新版本为1.6.3,并由10gen提供商业支持。

视觉中国的NoSQL之路:从MySQL到MongoDB

起因

  视觉中国网站(www.chinavisual.com)是国内最大的创意人群的专业网站。2009年以前,同很多公司一样,我们的CMS和社区产品都构建于PHP+Nginx+MySQL之上;MySQL使用了Master+Master的部署方案;前端使用自己的PHP框架进行开发;Memcached作为缓存;Nginx进行Web服务和负载均衡;Gearman进行异步任务处理。在传统的基于静态内容(如文章,资讯,帖子)的产品,这个体系运行良好。通过分级的缓存,数据库端实际负载很轻。2009年初,我们进行了新产品的开发。此时,我们遇到了如下一些问题。

  用户数据激增:我们的MySQL某个信息表上线1个月的数据就达到千万。我们之前忽略的很多数据,在新形势下需要跟踪记录,这也导致了数据量的激增;

  用户对于信息的实时性要求更高:对信息的响应速度和更新频度就要求更高。简单通过缓存解决的灵丹妙药不复存在;

  对于Scale-out的要求更高:有些创新产品的增长速度是惊人的。因此要求能够无痛的升级扩展,否则一旦停机,那么用户流失的速度也是惊人的;

  大量文件的备份工作:我们面向的是创意人群,产生的内容是以图片为主。需要能够对这些图片及不同尺寸的缩略图进行有效的备份管理。我们之前使用的Linux inotify+rsync的增量备份方案效果不佳;

  需求变化频繁:开发要更加敏捷,开发成本和维护成本要更低,要能够快速地更新进化,新功能要在最短的周期内上线。

  最初,我们试图完全通过优化现有的技术架构来解决以上问题:对数据时效性进一步分级分层缓存,减小缓存粒度;改进缓存更新机制(线上实时和线下异步更新)提高缓存命中率;尝试对业务数据的特点按照水平和垂直进行分表;使用MogileFS进行分布存储;进一步优化MySQL的性能,同时增加MySQL节点等。但很快发现,即便实施了上述方案,也很难完全解决存在的问题:过度依赖Memcached导致数据表面一致性的维护过于复杂,应用程序开发需要很小心,很多时候出现Memcached的失效会瞬间导致后端数据库压力过大;不同类型数据的特点不同,数据量差别也很大;分表的机制和方式在效率平衡上很难取舍;MogileFS对我们而言是脚小鞋大,维护成本远远超过了实际的效益;引入更多的MySQL数据库节点增大了我们的维护量,如何有效监控和管理这些节点又成了新的问题。虽然虚拟化可以解决部分问题,但还是不能令人满意;

  除了MySQL,能否找到一个更为简单、轻便的瑞士军刀呢?我们的目光投向了NoSQL的方案。

  候选方案

  最初,对于NoSQL的候选方案,我依据关注和熟悉程度,并且在甄别和选择合适的方案时特别制定了一些原则:是否节省系统资源,对于CPU等资源是否消耗过大;客户端/API支持,这直接影响应用开发的效率;文档是否齐全,社区是否活跃;部署是否简单;未来扩展能力。按以上几点经过一段测试后,我们候选名单中剩下Redis、MongoDB和Flare。

  Redis对丰富数据类型的操作很吸引人,可以轻松解决一些应用场景,其读写性能也相当高,唯一缺点就是存储能力和内存挂钩,这样如果存储大量的数据需要消耗太多的内存(最新的版本已经不存在这个问题)。

  Flare的集群管理能力令人印象深刻,它可以支持节点的动态部署,支持节点的基于权重的负载均衡,支持数据分区。同时允许存储大的数据,其key的长度也不受Memcached的限制。而这些对于客户端是透明的,客户端使用Memcached协议链接到Flare的proxy节点就可以了。由于使用集群,Flare支持fail-over,当某个数据节点宕掉,对于这个节点的访问都会自动被proxy节点forward到对应的后备节点,恢复后还可以自动同步。Flare的缺点是实际应用案例较少,文档较为简单,目前只在Geek使用。

  以上方案都打算作为一个优化方案,我从未想过完全放弃MySQL。然而,用MongoDB做产品的设计原型后,我彻底被征服了,决定全面从MySQL迁移到MongoDB。

  为什么MongoDB可以替代MySQL?

  MongoDB是一个面向文档的数据库,目前由10gen开发并维护,它的功能丰富,齐全,完全可以替代MySQL。在使用MongoDB做产品原型的过程中,我们总结了MonogDB的一些亮点:

  使用JSON风格语法,易于掌握和理解:MongoDB使用JSON的变种BSON作为内部存储的格式和语法。针对MongoDB的操作都使用JSON风格语法,客户端提交或接收的数据都使用JSON形式来展现。相对于SQL来说,更加直观,容易理解和掌握。

  Schema-less,支持嵌入子文档:MongoDB是一个Schema-free的文档数据库。一个数据库可以有多个Collection,每个Collection是Documents的集合。Collection和Document和传统数据库的Table和Row并不对等。无需事先定义Collection,随时可以创建。

  Collection中可以包含具有不同schema的文档记录。 这意味着,你上一条记录中的文档有3个属性,而下一条记录的文档可以有10个属性,属性的类型既可以是基本的数据类型(如数字、字符串、日期等),也可以是数组或者散列,甚至还可以是一个子文档(embed document)。这样,可以实现逆规范化(denormalizing)的数据模型,提高查询的速度。

图1 MongoDB是一个Schema-free的文档数据库

  图2是一个例子,作品和评论可以设计为一个collection,评论作为子文档内嵌在art的comments属性中,评论的回复则作为comment子文档的子文档内嵌于replies属性。按照这种设计模式,只需要按照作品id检索一次,即可获得所有相关的信息了。在MongoDB中,不强调一定对数据进行Normalize ,很多场合都建议De-normalize,开发人员可以扔掉传统关系数据库各种范式的限制,不需要把所有的实体都映射为一个Collection,只需定义最顶级的class。MongoDB的文档模型可以让我们很轻松就能将自己的Object映射到collection中实现存储。

图2 MongoDB支持嵌入子文档

  简单易用的查询方式:MongoDB中的查询让人很舒适,没有SQL难记的语法,直接使用JSON,相当的直观。对不同的开发语言,你可以使用它最基本的数组或散列格式进行查询。配合附加的operator,MongoDB支持范围查询,正则表达式查询,对子文档内属性的查询,可以取代原来大多数任务的SQL查询。

  CRUD更加简单,支持in-place update:只要定义一个数组,然后传递给MongoDB的insert/update方法就可自动插入或更新;对于更新模式,MongoDB支持一个upsert选项,即:“如果记录存在那么更新,否则插入”。MongoDB的update方法还支持Modifier,通过Modifier可实现在服务端即时更新,省去客户端和服务端的通讯。这些modifer可以让MongoDB具有和Redis、Memcached等KV类似的功能:较之MySQL,MonoDB更加简单快速。Modifier也是MongoDB可以作为对用户行为跟踪的容器。在实际中使用Modifier来将用户的交互行为快速保存到MongoDB中以便后期进行统计分析和个性化定制。

  所有的属性类型都支持索引,甚至数组:这可以让某些任务实现起来非常的轻松。在MongoDB中,“_id”属性是主键,默认MongoDB会对_id创建一个唯一索引。

  服务端脚本和Map/Reduce:MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。MongoDB不支持事务级别的锁定,对于某些需要自定义的“原子性”操作,可以使用Server side脚本来实现,此时整个MongoDB处于锁定状态。Map/Reduce也是MongoDB中比较吸引人的特性。Map/Reduce可以对大数据量的表进行统计、分类、合并的工作,完成原先SQL的GroupBy等聚合函数的功能。并且Mapper和Reducer的定义都是用Javascript来定义服务端脚本。

  性能高效,速度快: MongoDB使用c++/boost编写,在多数场合,其查询速度对比MySQL要快的多,对于CPU占用非常小。部署也很简单,对大多数系统,只需下载后二进制包解压就可以直接运行,几乎是零配置。

  支持多种复制模式: MongoDB支持不同的服务器间进行复制,包括双机互备的容错方案。

  Master-Slave是最常见的。通过Master-Slave可以实现数据的备份。在我们的实践中,我们使用的是Master-Slave模式,Slave只用于后备,实际的读写都是从Master节点执行。

  Replica Pairs/Replica Sets允许2个MongoDB相互监听,实现双机互备的容错。

  MongoDB只能支持有限的双主模式(Master-Master),实际可用性不强,可忽略。

  内置GridFS,支持大容量的存储:这个特点是最吸引我眼球的,也是让我放弃其他NoSQL的一个原因。GridFS具体实现其实很简单,本质仍然是将文件分块后存储到files.file和files.chunk 2个collection中,在各个主流的driver实现中,都封装了对于GridFS的操作。由于GridFS自身也是一个Collection,你可以直接对文件的属性进行定义和管理,通过这些属性就可以快速找到所需要的文件,轻松管理海量的文件,无需费神如何hash才能避免文件系统检索性能问题, 结合下面的Auto-sharding,GridFS的扩展能力是足够我们使用了。在实践中,我们用MongoDB的GridFs存储图片和各种尺寸的缩略图。

图3 MongoDB的Auto-sharding结构

  内置Sharding,提供基于Range的Auto Sharding机制:一个collection可按照记录的范围,分成若干个段,切分到不同的Shard上。Shards可以和复制结合,配合Replica sets能够实现Sharding+fail-over,不同的Shard之间可以负载均衡。查询是对客户端是透明的。客户端执行查询,统计,MapReduce等操作,这些会被MongoDB自动路由到后端的数据节点。这让我们关注于自己的业务,适当的时候可以无痛的升级。MongoDB的Sharding设计能力最大可支持约20 petabytes,足以支撑一般应用。

  第三方支持丰富: MongoDB社区非常活跃,很多开发框架都迅速提供了对MongDB的支持。不少知名大公司和网站也在生产环境中使用MongoDB,越来越多的创新型企业转而使用MongoDB作为和Django,RoR来搭配的技术方案。

  实施结果

  实施MonoDB的过程是令人愉快的。我们对自己的PHP开发框架进行了修改以适应MongoDB。在PHP中,对MongoDB的查询、更新都是围绕Array进行的,实现代码变得很简洁。由于无需建表,MonoDB运行测试单元所需要的时间大大缩短,对于TDD敏捷开发的效率也提高了。当然,由于MongoDB的文档模型和关系数据库有很大不同,在实践中也有很多的困惑,幸运的是,MongoDB开源社区给了我们很大帮助。最终,我们使用了2周就完成了从MySQL到MongoDB的代码移植比预期的开发时间大大缩短。从我们的测试结果看也是非常惊人,数据量约2千万,数据库300G的情况下,读写2000rps,CPU等系统消耗是相当的低(我们的数据量还偏小,目前陆续有些公司也展示了他们的经典案例:MongoDB存储的数据量已超过 50亿,>1.5TB)。目前,我们将MongoDB和其他服务共同部署在一起,大大节约了资源。

  一些小提示

  切实领会MongoDB的Document模型,从实际出发,扔掉关系数据库的范式思维定义,重新设计类;在服务端运行的JavaScript代码避免使用遍历记录这种耗时的操作,相反要用Map/Reduce来完成这种表数据的处理;属性的类型插入和查询时应该保持一致。若插入时是字符串“1”,则查询时用数字1是不匹配的;优化MongoDB的性能可以从磁盘速度和内存着手;MongoDB对每个Document的限制是最大不超过4MB;在符合上述条件下多启用Embed Document, 避免使用DatabaseReference;内部缓存可以避免N+1次查询问题(MongoDB不支持joins)。

  用Capped Collection解决需要高速写入的场合,如实时日志;大数据量情况下,新建同步时要调高oplogSize的大小,并且自己预先生成数据文件,避免出现客户端超时;Collection+Index合计数量默认不能超过24000;当前版本( 100;

SELECT * FROM `mobile_params` WHERE name = '外观设计' AND value = '直板';

注:参数表为了方便,把数值和字符串统一保存成字符串,实际使用时,MySQL允许在字符串类型的字段上进行数值类型的查询,只是需要进行类型转换,多少会影响一点性能。

两条SQL的结果取交集得到想要的MOBILE_IDS,再到mobiles表查询即可:

SELECT * FROM `mobiles` WHERE mobile_id IN (MOBILE_IDS)
如果使用MongoDB的话,应该如何存取数据呢?

如果使用MongoDB的话,虽然理论上可以采用和MySQL一样的设计方案,但那样的话就显得无趣了,没有发挥出MongoDB作为文档型数据库的优点,实际上使用MongoDB的话,和MySQL相比,形象一点来说,可以合二为一:

db.getCollection("mobiles").ensureIndex({
    "params.name": 1,
    "params.value": 1
});
 
db.getCollection("mobiles").insert({
    "_id": 1,
    "name": "ME525",
    "brand": "摩托罗拉",
    "params": [
        {"name": "待机时间", "value": 200},
        {"name": "外观设计", "value": "直板"}
    ]
});
 
db.getCollection("mobiles").insert({
    "_id": 2,
    "name": "E7",
    "brand": "诺基亚",
    "params": [
        {"name": "待机时间", "value": 500},
        {"name": "外观设计", "value": "滑盖"}
    ]
});

如果想查询待机时间大于100小时,并且外观设计是直板的手机,需按照如下方式查询:

db.getCollection("mobiles").find({
    "params": {
        $all: [
            {$elemMatch: {"name": "待机时间", "value": {$gt: 100}}},
            {$elemMatch: {"name": "外观设计", "value": "直板"}}
        ]
    }
});

注:查询中用到的$all,$elemMatch等高级用法的详细介绍请参考官方文档中相关说明。

MySQL需要多个表,多次查询才能搞定的问题,MongoDB只需要一个表,一次查询就能搞定,对比完成,相对MySQL而言,MongoDB显得更胜一筹,至少本例如此。

 

 

 

关于NoSQL,你必须知道的九件事

1.  理解ACID与BASE的区别(ACID是关系型数据库强一致性的四个要求,而BASE是NoSQL数据库通常对可用性及一致性的弱要求原则,它们的意思分别是,ACID:atomicity, consistency, isolation, durability;BASE:BasicallyAvailable, Soft-state, Eventually Consistent。同时有意思的是ACID在英语里意为酸,BASE意思为碱)

2.  理解持久化与非持久化的区别。这么说是因为有的NoSQL系统是纯内存存储的。

3.  你必须意识到传统有关系型数据库与NoSQL系统在数据结构上的本质区别。传统关系型数据库通常是基于行的表格型存储,而NoSQL系统包括了列式存储(Cassandra)、key/value存储(Memcached)、文档型存储(CouchDB)以及图结构存储(Neo4j)

4.  与传统关系数据库有统一的SQL语言操作接口不同,NoSQL系统通常有自己特有的API接口。

5.  在架构上,你必须搞清楚,NoSQL系统是被设计用于成百上千台机器的集群中的,而非共享型数据库系统的架构。

6.  在NoSQL系统中,可能你得习惯一下不知道你的数据具体存在何处的情况。

7.  在NoSQL系统中,你最好习惯它的弱一致性。”eventually consistent”(最终一致性)正是BASE原则中的重要一项。比如在Twitter,你在Followers列表中经常会感受到数据的延迟。

8.  在NoSQL系统中,你要理解,很多时候数据并不总是可用的。

9.  你得理解,有的方案是拥有分区容忍性的,有的方案不一定有。

antirez 的Redis 宣言!

1.  Redis 是一个操作数据结构的语言工具,它提供基于TCP的协议以操作丰富的数据结构。在Redis中,数据结构这个词的意义不仅表示在某种数据结构上的操作,更包括了结构本身及这些操作的时间空间复制度。

2.  Redis 定位于一个内存数据库,正是由于内存的快速访问特性,才使得Redis能够有如此高的性能,才使得Redis能够轻松处理大量复杂的数据结构,Redis会尝试其它的存储方面的选择,但是永远不会改变它是一个内存数据库的角色。

3.  Redis 使用基础的API操作基础的数据结构,Redis的API与数据结构一样,都是一些最基础的元素,你几乎可以将任何信息交互使用此API格式表示。作者调侃说,如果有其它非人类的智能生物存在,他们也能理解Redis的API。因为它是如此的基础。

4.  Redis 有着诗一般优美的代码,经常有一些不太了解Redis 原则的人会建议Redis采用一些其它人的代码,以实现一些Redis 未实现的功能,但这对我们来说就像是非要给《红楼梦》接上后四十回一样。(作者此处用了莎士比亚的比喻)

5.  Redis 始终避免复杂化,我们认为设计一个系统的本质,就是与复杂化作战。我们不会为了一个小功能而往源码里添加上千行代码,解决复杂问题的方法就是让复杂问题永远不要提复杂的问题。

6.  Redis 支持两个层成的API,第一个层面包含部分操作API,但它支持用于分布式环境下的Redis。第二个层面的API支持更复杂的multi-key操作。它们各有所长,但是我们不会推出两者都支持的API,但我们希望能够提供实例间数据迁移的命令,并执行multi-key操作。

7.  我们以优化代码为乐,我们相信编码是一件辛苦的工作,唯一对得起这辛苦的就是去享受它。如果我们在编码中失去了乐趣,那最好的解决办法就是停下来。我们决不会选择让Redis不好玩的开发模式。

NoSQL开篇——为什么要使用NoSQL

NoSQL在2010年风生水起,大大小小的Web站点在追求高性能高可靠性方面,不由自主都选择了NoSQL技术作为优先考虑的方面。今年伊始,InfoQ中文站有幸邀请到凤凰网的孙立先生,为大家分享他之于NoSQL方面的经验和体会。

  非常荣幸能受邀在InfoQ开辟这样一个关于NoSQL的专栏,InfoQ是我非常尊重的一家技术媒体,同时我也希望借助InfoQ,在国内推动NoSQL的发展,希望跟我一样有兴趣的朋友加入进来。这次的NoSQL专栏系列将先整体介绍NoSQL,然后介绍如何把NoSQL运用到自己的项目中合适的场景中,还会适当地分析一些成功案例,希望有成功使用NoSQL经验的朋友给我提供一些线索和信息。

  NoSQL概念

  随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一词最早于1998年被用于一个轻量级的关系数据库的名字。)

  NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用。比如cdb、qdbm、bdb数据库。

  传统关系数据库的瓶颈

  传统的关系数据库具有不错的性能,高稳定型,久经历史考验,而且使用简单,功能强大,同时也积累了大量的成功案例。在互联网领域,MySQL成为了绝对靠前的王者,毫不夸张的说,MySQL为互联网的发展做出了卓越的贡献。

  在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。

  到了最近10年,网站开始快速发展。火爆的论坛、博客、sns、微博逐渐引领web领域的潮流。在初期,论坛的流量其实也不大,如果你接触网络比较早,你可能还记得那个时候还有文本型存储的论坛程序,可以想象一般的论坛的流量有多大。

  Memcached+MySQL

  后来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技术产品。

  Memcached作为一个独立的分布式的缓存服务器,为多个web服务器提供了一个共享的高性能缓存服务,在Memcached服务器上,又发展了根据hash算法来进行多台Memcached缓存服务的扩展,然后又出现了一致性hash来解决增加或减少缓存服务器导致重新hash带来的大量缓存失效的弊端。当时,如果你去面试,你说你有Memcached经验,肯定会加分的。

  Mysql主从读写分离

  由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。

  分表分库

  随着web2.0的继续高速发展,在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但是由于在互联网几乎没有成功案例,性能也不能满足互联网的要求,只是在高可靠性上提供了非常大的保证。

  MySQL的扩展性瓶颈

  在互联网,大部分的MySQL都应该是IO密集型的,事实上,如果你的MySQL是个CPU密集型的话,那么很可能你的MySQL设计得有性能问题,需要优化了。大数据量高并发环境下的MySQL应用开发越来越复杂,也越来越具有技术挑战性。分表分库的规则把握都是需要经验的。虽然有像淘宝这样技术实力强大的公司开发了透明的中间件层来屏蔽开发者的复杂性,但是避免不了整个架构的复杂性。分库分表的子库到一定阶段又面临扩展问题。还有就是需求的变更,可能又需要一种新的分库方式。

  MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。

  关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

  NOSQL的优势

  易扩展

  NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。

  大数据量,高性能

  NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。而NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。

  灵活的数据模型

  NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的web2.0时代尤其明显。

  高可用

  NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。

  总结

  NoSQL数据库的出现,弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本。

  MySQL和NoSQL都有各自的特点和使用的应用场景,两者的紧密结合将会给web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,NoSQL关注在存储上。

你需要知道的NoSQL数据库10件事

NoSQL的5个优势

  1.弹性扩展

  多年来,数据库管理员一直依赖于向上扩展(scale up)-随着数据库负载的增加购买更大的数据库服务器―而不是向外扩展-随着负载的增加将数据库分不到多个不同的主机上。然而,随着每秒事务数与可用性需求的提高,以及数据库往云或虚拟环境的迁移,向外扩展到廉价硬件的经济优势越来越难以抵挡。

  RDBMS或许比较难以在廉价的集群上进行向外扩展,但是,NoSQL数据库的新品从设计之初就是为了利用新节点的优势进行透明扩展,他们通常在设计时就考虑使用低成本的廉价硬件。

  2.大数据量

  在过去10年,与每秒事务数的增长超出了认知一样,存储的数据的规模也出现了极大的增长。O’Reilly明智的称此为”数据的工业革命。”RDBMS的容量也在增长以匹配这些数据的增长,但是,与每秒事务数一样,单个RDBMS可有效管理的数据规模限制让部分企业越来越难以忍受。今天,大规模数据量可以交由NoSQL系统来处理,比如Hadoop,超过目前最大的RDBMS可以管理的数据规模。

  3.  再见了,DBA(回头见,DBA?)

  这些年,虽然RDBMS的提供商宣称推出了很多的可管理性方面的改进,高端的RDBMS系统还是只能交由昂贵的、高度受训的DBA来进行维护。高端RDBMS系统从设计到安装以及后续的调优,都需要DBA们深度介入。

  从理论上,通常,NoSQL数据库的最初的设计目标就是更少的管理介入:自动修复、数据分布以及更简单的数据模型,从而更少的管理与调优需求。实际上,关于DBA将死的谣言很可能被略微放大了。对于任何关键的数据存储,总是需要有人来关心它的性能以及可用性。

  4.经济性

  NoSQL数据库通常使用廉价服务器集群来管理暴增的数据与事务规模,而RDBMS倾向于依赖昂贵的专有服务器与存储系统。其结果是,NoSQL数据库的每GB数据或每秒事务数的成本要远远低于RDBMS,使得你可以以更低的价格来存储与处理更多的数据。

  5.灵活的数据模型

  在大量的生产环境数据库中,变更管理是一个非常棘手的问题。哪怕是对数据模型的很小的变更,在RDBMS中也需要进行小心的管理,甚至还需要停机或降低服务级别。

  在数据模型的限制这一点上,NoSQL数据库要宽松的多,或者完全不存在。 NoSQL的键值存储(Keyvalue Store)与文档数据库(Document Database)允许应用在一个数据单元中存入它想要的任何结构。即使是定义更加严格的基于BigTable的NoSQL数据库,通常也允许创建新的字段而不致带来麻烦。

  其结果是,应用的变更与数据库结构的变更不需要绑定在一个变更单元中进行管理。理论上,这可以提高应用的迭代速度,然而,显然,如果应用无法管理数据的完整性,它将带来不良的副作用。

  NoSQL的5个挑战

  NoSQL数据库的可能性空间引发了大量的关注,但是,在它们成为企业级应用的主流之前,还有大量的障碍有待克服。下面是几个主要的挑战。

  1.成熟度

  RDBMS已经存在了很长一段时间。 NoSQL的支持者认为它们的年纪是它们过时的象征,但是,对于大部分CIO(首席信息官)来讲,RDBMS的成熟度是可以让人放心的。通常,RDBMS 系统都很稳定,功能也很丰富。相比而言,大部分NoSQL的替代品都还处于前一生产环境阶段,还有大量的关键特性有待实现。

  生活在科技前沿对于大部分开发人员来讲,是令人兴奋的,但是,企业在实施时必须非常谨慎。

  2.支持力度

  企业还希望获得保证,当关键系统出现故障时,他们可以获得及时而有效的支持。所有的RDBMS提供商都在竭尽全力地为企业提供高级别的支持。

  相比而言,大部分的NoSQL系统都是开源项目,虽然,每一个NoSQL数据库通常都会有一家或多家公司为其提供支持,这些公司通常都是小的创业公司,没有能力提供全球的支持,没有足够的支持资源,或者没有类似于Oracle、Microsoft或者IBM的信用。

  3.分析与商业智能

  NoSQL数据库经过不断的演化,已经可以满足现代的Web 2。0应用的扩展需求。相应地,它们的大部分功能集也旨在满足这些应用的需求。然而,应用程序中的数据的价值,要超出一个典型的Web应用的插入-阅读-更新-删除的周期。从公司数据库中挖掘信息以提高公司的效率与竞争力的业务,以及商业智能(BI)是所有大中型公司的关键议题。

  NoSQL数据库提供了新型的工具来做即时的查询与分析。哪怕是一个简单的查询,也需要可观的编程技能,通常使用的BI工具都无法访问NoSQL数据库。

  稍显宽慰的是,还有类似于HIVE与PIG的这类解决方案,通过它们可以较为简单地访问Hadoop集群中的数据,或许最终,可以较为简单的访问其他的 NoSQL数据库。Quest软件公司开发一个产品,Toad For Cloud Database,它提供了对各种不同的NoSQL数据库的即时查询功能。

  4.管理

  NoSQL的设计目标可能是提供零-管理的解决方案,但是,当前的现实是,此目标远远没有实现。目前的NoSQL系统需要大量的技能来进行安装,以及需要大量的努力来进行维护。

  5.专业技能

  坦率的讲,目前世界上有上百万的程序员非常熟悉RDBMS的原理与编程,他们分布在各种业务场景中。相比而言,几乎每一个NoSQL开发人员都还处于学习阶段。随着时间的流逝,这种状况将得到解决,但是,现在,寻找一个有经验的RDBMS开发人员与RDBMS管理员要比寻找一个NoSQL专家要容易的多。

  结论

  NoSQL数据库正在成为越来越多的数据库环境的重要的组成部分,如果使用得当的话,它可以提供实实在在的收益。然而,企业在推进它们的使用时需要非常谨慎,需要明白这些数据库的相关内在限制与问题。

NoSQL生态系统大检阅 不同特性大比拼

虽然NoSQL很火热,但是真正应用NoSQL的用户不多。本文将为大家以对比的形式来介绍不同NoSQL产品的特点,希望对大家有所帮助。

  空前的数据量正在驱动商业寻找传统关系型数据库的替代方案,它已经为我们服务30多年了(今年5月份ACM刚刚给关系型数据庆祝40岁生日).总体来讲,这些替代方案就是目前知名的“NoSQL数据库.”

  关系型数据库的基本问题是无法处理许多现代的工作负载.有三个具体的问题领域:向外扩展(Scaleout)类似于Digg(3TB的绿色徽章数据)或Facebook(50T的收件箱搜索数据)或Ebay(总共2PB的数据)的数据集,单机性能限制以及僵化的概要设计.

  商业上(包含Rackspace Cloud公司)需要寻找新的方式来存储并扩展大规模的数据.我最近写了一篇关于Cassandra的文章,一个我们投入了资源的非关系型数据库.还有另外一些正在运作中的非关系型数据库,它们汇总在一起被我们称为”NoSQL运动”.

  “NoSQL”这个术语实际上是由一个Rackspace的员工Eric Evans最先提出的,当时来自Last.fm网站的Johan Oskarsson提议组织一次开源分布式数据库的研讨会.这个名称与概念就一起流行了起来.

  有些人反对NoSQL这个说法,因为它听起来像是仅仅表明了我们不做什么,而不是我们在做什么.事实确实是这样,我也基本同意此说法,但是这个术语仍然有其价值,因为当关系型数据库是你所知道的唯一工具时,每个问题看起来都像个拇指(俗语,如果你手里有一个锤子,你看到什么都是钉子,译者补充).NoSQL这个术语起码让人们知道还有其他的选项可供选择.但是,当关系型数据库是解决问题的最佳工具时,我们并不是反关系型数据库者;它的涵义应该是“不仅仅有SQL(Not Only SQL)”而不是“不再有SQL(No SQL atall)”.

  有关NoSQL名称的一个真实的忧虑是,它是如此大的一个概念,以致于差异巨大的设计都可以涵盖其中.如果在讨论各种产品时没有搞清楚这一点,就会导致概念混乱.因此,我建议大家沿着下面三个维度来思考这些数据库选项: 可伸缩性(scalability)、数据模型与查询模型(data andquery model)以及持久化设计(persistencedesign).

  我选择了10种NoSQL数据库作为示例.这不是一份详尽的清单,但是这里讨论的概念对于评估其他的NoSQL数据库也至关重要.

  可伸缩性(Scalability)

  通过使用复制,就可以轻易扩展读的规模,因此,每当我在此文中谈到规模伸缩(scaling),都是表示通过自动分区将数据分布到多台机器以扩展写的规模.我们将做这种事情的系统称为“分布式数据库”.它们包括Cassandra、HBase、Riak、Scalaris、Voldemort以及其他很多类似的系统.如果你的写容量或写数据大小已经无法在一台机器上进行处理,如果你不想自己手工来管理分区的话,这些就是你的唯一选项了.(你不会这么做吧?)

  人们使用分布式数据库主要关注两件事情: 1) 是否支持多个数据中心以及2) 能否在对应用透明的前提下往正在运行的集群中添加新机器的能力.

  非分布式NoSQL数据库包括CouchDB、MongoDB、Neo4j、Redis以及TokyoCabinet.它们可作为分布式系统的持久层;MongoDB提供了受限制的数据分片(Sharding)功能,CouchDB也有一个独立的Lounge项目来支持做类似的分片功能,TokyoCabinet可用作Voldemort的存储引擎.

  数据模型与查询模型

  NoSQL数据库之间的数据模型与查询API千差万别.

  部分重点内容介绍:

  Cassandra与HBase共同使用的ColumnFamily模型都是受到Google的Bigtable论文第2节的启发.(Cassandra丢弃了历史版本,并增加了超级列(SuperColumn)的概念).在这两个系统中,都有与你之前看到的关系型数据库类似的行/列概念,但是此处的行是稀疏的行:你想要一行有多少列,一行就可以有多少列,这些列并不需要事先定义好.

  键值(Key/value)模型是最简单也最容易实现的模型,但是,如果你仅想对值(Value)的一部分进行查询/更新时,它的效率会比较低.要想在一个分布式的键值上,实现更加复杂的结构也会非常困难.

  文档数据库实际上是更高级的键/值(Key/Value)数据库,允许在每个键上关联嵌套的值.相对于每次简单地返回整个BLOB(二进制大对象)来讲,文档数据库支持更高效的查询.

  Neo4j拥有一个非常独特的数据模型,它以节点与边的形式在图中存储对象与关系.对于适合这个模型(例如,分层数据)的查询,它的性能可能会达到其替代选项的1000倍.

  Scalaris的独特之处在于,它可以提供跨越多个键的分布式事务.(关于一致性与可用性的权衡的讨论超出了本文的范围,但是,在评估分布式系统时,它也是需要记住的一方面.)

  持久化设计

  关于持久化设计,我的意思是“数据在内部是如何存储的?”

  持久化模型可以为我们提供大量关于这些数据库适合处理多大工作负载的信息.

  内存数据库非常非常快(单台机器上的Redis可以处理100,000次操作/秒),但是无法处理超过可用内存的数据集.持久性(Durability,数据不会由于服务器崩溃或停电而丢失)也是个问题;在两次刷新到磁盘的时间间隔内预期数据丢失量可能非常大.Scalaris是我们此列表中唯一的内存数据库,它通过复制来解决持久性的问题,但是,由于它不支持跨越多个数据中心,因此,如果遇到类似电源故障一类的问题数据仍将非常脆弱.

  在为了持久性写入一个仅可追加的提交日志之后,Memtable与SSTable会缓冲内存中的写操作.在接受了足够多的写操作之后(Memtable达到一定的阈值),就会对memtable中的数据进行排序,并一次性写入到磁盘,写入的文件就是一个“sstable.”这样它就可以提供接近于内存处理的性能,因为它不涉及任何检索操作,同时又可以避免纯粹在内存中的方法那样遭遇持久性问题.(在前面引用的Bigtable论文的第5.3与5.4两节,以及论文日志结构的合并树(TheLog-Structuredmerge-tree)中对此都有详细的描述)

  几乎从有数据库开始,B-树就开始在数据库中使用了.它们提供健壮的索引支持,但是在旋转磁盘(仍然是目前最经济实用的存储介质)上, 它的性能表现比较差,因为它读写任何内容都会涉及到多次磁盘检索.

  CouchDB的仅可做追加操作的B-树(Append-OnlyB-tree)是一个比较有趣的变体,它以限制CouchDB并发写(one write at a time)的代价避免了其检索的开销.

  结论

  NoSQL运动在2009年取得了爆发性的效果,因为越来越多的企业需要处理大规模的数据.Rackspace Cloud公司很高兴在NoSQL运动扮演了一个较早期的角色,还会持续为Cassandra投入资源并支持与NoSQL East类似的活动.

NoSQL数据库利弊分析:五大优势五大挑战

关系数据库模型已经流行了几十年了,但是一种新类型的数据库——被称为NoSQL,正在引起企业的注意。下面是关于它的优势和劣势的一个概述。二十多年以来,对数据库管理来说,关系数据库(RDBMS)模型一直是一个占统治地位的数据库模型。但是,今天,非关系数据库,“云”数据库,或“NoSQL”数据库作为关系数据库以外的一些选择,正在引起大家的广泛关注。在这篇文章里,我们将主要关注那些非关系的NoSQL数据库的十大利弊:包括五大优势和五大挑战。

NoSQL的五大优势

1.灵活的可扩展性

多年以来,数据库管理员们都是通过“纵向扩展”的方式(当数据库的负载增加的时候,购买更大型的服务器来承载增加的负载)来进行扩展的,而不是通过“横向扩展”的方式(当数据库负载增加的时候,在多台主机上分配增加的负载)来进行扩展。但是,随着交易率和可用性需求的增加,数据库也正在迁移到云端或虚拟化环境中,“横向扩展”在commodity hardware方面的经济优势变得更加明显了,对各大企业来说,这种“诱惑”是无法抗拒的。

在commodity clusters上,要对RDBMS做“横向扩展”,并不是很容易,但是各种新类型的NoSQL数据库主要是为了进行透明的扩展,来利用新节点而设计的,而且,它们通常都是为了低成本的commodity hardware而设计的。

2.大数据

在过去的十年里,正如交易率发生了翻天覆地的增长一样,需要存储的数据量也发生了急剧地膨胀。O’Reilly把这种现象称为:“数据的工业革命”。为了满足数据量增长的需要,RDBMS的容量也在日益增加,但是,对一些企业来说,随着交易率的增加,单一数据库需要管理的数据约束的数量也变得越来越让人无法忍受了。现在,大量的“大数据”可以通过NoSQL系统(例如:Hadoop)来处理,它们能够处理的数据量远远超出了最大型的RDBMS所能处理的极限。

3.“永别了”!DBA们!

在过去的几年里,虽然一些RDBMS供应商们声称在可管理性方面做出了很多的改进,但是高端的RDBMS系统维护起来仍然十分昂贵,而且还需要训练有素的DBA们的协助。DBA们需要亲自参与高端的RDBMS系统的设计,安装和调优。

NoSQL数据库从一开始就是为了降低管理方面的要求而设计的:从理论上来说,自动修复,数据分配和简单的数据模型的确可以让管理和调优方面的要求降低很多。但是,DBA的死期将至的谣言未免有些过于夸张了。总是需要有人对关键性的数据库的性能和可用性负责的。

4.经济

NoSQL数据库通常使用廉价的commodity servers集群来管理膨胀的数据和事务数量,而RDBMS通常需要依靠昂贵的专有服务器和存储系统来做到这一点。使用NoSQL,每GB的成本或每秒处理的事务的成本都比使用RDBMS的成本少很多倍,这可以让你花费更低的成本存储和处理更多的数据。

5.灵活的数据模型

对于大型的生产性的RDBMS来说,变更管理是一件很令人头痛的事情。即使只对一个RDBMS的数据模型做了很小的改动,也必须要十分小心地管理,也许还需要停机或降低服务水平。NoSQL数据库在数据模型约束方面是更加宽松的,甚至可以说并不存在数据模型约束。NoSQL的主键值数据库和文档数据库可以让应用程序在一个数据元素里存储任何结构的数据。即使是规定更加严格的基于“大表”的NoSQL数据库(例如:Cassandra, HBase)通常也允许创建新列,这并不会造成什么麻烦。

应用程序变更和数据库模式的变更并不需要作为一个复杂的变更单元来管理。从理论上来说,这可以让应用程序迭代的更快,但是,很明显,如果应用程序无法维护数据的完整性,那么这会带来一些不良的副作用。

NoSQL的五大挑战

NoSQL的种种承诺引发了一场热潮,但是在它们得到主流的企业的青睐以前,它们还有许多困难需要克服。下面是NoSQL需要面对的一些挑战。

1.成熟度

RDBMS系统已经发展很长时间了。NoSQL的拥护者们认为,RDBMS系统那超长的发展的年限恰恰表示它们已经过时了,但是对于大多数的CIO们来说,RDBMS的成熟度更加令它们放心。大多数情况下,RDBMS系统更加稳定,而且功能也更加丰富。相比之下,大多数的NoSQL数据库都是pre-production版本,许多关键性的功能还有待实现。

对于大多数开发者来说,处于技术的最前沿的确是很令人兴奋的,但是企业应该怀着极端谨慎的态度来处理此事。

2.支持

企业都希望能得到这样的保证:如果一个关键性的系统出现问题了,他们可以获得及时有效的支持。所有的RDBMS供应商都在竭尽全力地提供高水平的企业支持。

相反,大多数的NoSQL系统都是开源项目,虽然对于每个NoSQL数据库来说,通常也会有一个或多个公司对它们提供支持,但是那些公司通常是小型的创业公司,在支持的范围,支持的资源,或可信度方面,它们和Oracle, Microsoft或IBM是无法相提并论的。

3.分析和商业智能化

NoSQL数据库现在已经可以满足现代的Web2.0应用程序的高度的可扩展性的要求了。这直接导致的结果是,它们的大多数功能都是面向这些应用程序而设计的。但是,在一个应用程序中,具有商业价值的数据早就已经超出了一个标准的Web应用程序需要的“插入-读取-更新-删除”的范畴了。在公司的数据库中进行商业信息的挖掘可以提高企业的效率和竞争力,而且对于所有的中到大型的公司来说,商业智能化(BI)一直是一个至关重要的IT问题。

NoSQL数据库几乎没有提供什么专用的查询和分析工具。即使是一个简单的查询,也要求操作者具有很高超的编程技术,而且,常用的BI工具是无法连接到NoSQL的。

像HIVE或PIG那样的新出现的一些解决方案在这方面可以提供一些帮助,它们可以让访问Hadoop集群中的数据变得更加容易,最后也许还会支持其他的NoSQL数据库。Quest软件已经开发了一个产品——Toad for Cloud Databases——它给各种NoSQL数据库提供了专用的查询功能。

4.管理

NoSQL的设计目标是提供一个“零管理”的解决方案,但是目前来说,还远远没有达到这个目标。安装NoSQL还是需要很多技巧的,同时,维护它也需要付出很多的努力。

5.专业知识

毫不夸张地说,全世界有数百万的开发者,他们都对RDBMS的概念和编程方法很熟悉,在每个业务部门中都有这样的开发者。相反,几乎每一个NoSQL开发者都正处于学习状态中。虽然这种情况会随着时间的推移而改变,但是现在,找到一些有经验的RDBMS程序员或管理员要比找到一个NoSQL专家容易的多。

结论

NoSQL数据库正在逐渐地成为数据库领域中不可或缺的一部分,如果使用方法得当的话,能获得很多的好处。但是,企业应该谨慎行事,要充分地认识到这些数据库的一些限制和问题。

SQL or NoSQL——云计算环境中该选择谁?

NoSQL和SQL之间真正的差异是什么?实质上,是因为不同的访问模式导致了NoSQL和SQL可扩展性和性能上的不同。

NoSQL只允许数据在受限的预定义模式访问。例如DHT (Distributed Hash Table)通过hashtable API访问。其他NoSQL数据服务访问模式同样受限。因此可扩展性和性能结构是可预测和可靠的。

而在SQL中,访问模式预先是不知道的,SQL是一种通用语言,允许数据以各种方式访问,程序员也对SQL语句的执行能力控制有限。

换句话说,在SQL中,数据模型不执行特定的工作方式与数据。强调建立数据完整性、简洁性、标准化和抽象化。这对于所有大型复杂的应用极为重要。

为什么是NoSQL

NoSQL提供的方法对于SQL数据库来说有巨大的优势。因为它允许应用程序扩展的新的水平。新的数据服务基于真正可扩展的结构和体系构建云、构建分布式。这对于应用开发来说是非常有吸引力的。无需DBA,无需复杂的SQL查询。

这是不小的问题,一个好程序员自由选择一个数据模型,使用熟悉的工具写应用程序,减少对他人的依赖于,并测试和优化的代码,而不做猜测或一个黑盒(DB)的计数。

这些都是NoSQL运动的所有主要优势,但NoSQL也非万能,具体而言,数据模型的选择、接口规范以及当前面临的新业务比如移动业务数据的处理问题,都是NoSQL无法回避的。

NoSQL绝非万能

数据模型

如果没有一个统一的、定义良好的数据模型,无论采用何种技术都有缺陷。

SQL的数据模型定义了高度结构化的数据结构,以及对这些结构之间关系的严格定义。在这样的数据模型上执行的查询操作会比较局限,而且可能会导致复杂的数据遍历操作。但是数据结构的复杂性及查询的复杂性,会导致系统产生如下的一些限制:比如当数据量增长到一台机器已经不能容纳,我们需要将不同的数据表分布到不同的机器;如果你的结构化数据并没有那么强,或者对每一行数据的要求比较灵活,那可能关系型的数据模型就太过严格了;再有,使用简单的查询语言可能会导致应用层的逻辑更复杂,但是这样可以将存储系统的工作简单化,让它只需要响应一些简单的请求。

此外,NoSQL数据库并非是唯一适合存储大量数据或大型数据,显然,通过良好的分区设计,SQL数据库也可以获得极好的扩展性。

接口和互操作问题

不可否认,NoSQL的数据服务接口还有待规范。比如DHT,这是一个简单的接口,但仍旧没有标准的语义。每个DHT服务都使用其自己的一套接口。另一个大问题是不同的数据结构,如 DHT和binary tree,只是作为一个例子,共享数据对象。所有这些服务中,指针没有内在的语义。事实上,这些服务中,处理互操作性是开发者的职责,这一点很很重要,尤其是当需要数据被多个服务访问时。一个简单的例子:后台工作由Java实现,Web服务类工作由PHP实现,数据可以被轻易地从两个域访问数据吗?显然,人们可以使用Web服务作为前端数据访问层,但是,NoSQL有可能让事情变得更复杂,并降低了业务敏捷性,灵活性和性能,同时增加了开发工作量。

移动业务

在移动业务领域,需要一套工具,这套工具不仅要有可扩展性,而且还易于管理并且稳定,并在云上有一个固定的设置服务器。当系统出现问题的时候,可以不需要通过判断整个系统或开发平台来诊断问题,而是通过远程访问——这正是运维经理们所要面对的问题,但是在目前NoSQL所能提供的服务功能来看,很难实现,即便是Amazon的托管环境。

SQL和NoSQL如何结合?

总而言之,在NoSQL和SQL的选择上,需要了解到以下内容:

数据模型及操作模型:你的应用层数据模型是行、对象还是文档型的呢?这个系统是否能支持你进行一些统计工作呢?

可靠性:当你更新数据时,新的数据是否立刻写到持久化存储中去了?新的数据是否同步到多台机器上了?

扩展性:你的数据量有多大,单机是否能容下?你的读写量求单机是否能支持?

分区策略:考虑到你对扩展性,可用性或者持久性的要求,你是否需要一份数据被存在多台机器上?你是否需要知道数据在哪台机器上,以及你能否知道。

一致性:你的数据是否被复制到了多台机器上,这些分布在不同点的数据如何保证一致性?

事务机制:你的业务是否需要ACID的事务机制?

单机性能:如果你打算持久化的将数据存在磁盘上,哪种数据结构能满足你的需求(你的需求是读多还是写多)?写操作是否会成为磁盘瓶颈?

负载可评估:对于一个读多写少的应用,诸如响应用户请求的web应用,我们总会花很多精力来关注负载情况。你可能需要进行数据规模的监控,对多个用户的数据进行汇总统计。你的应用场景是否需要这样的功能呢?

使用NoSQL架构实现SQL数据库?

使用NoSQL的基础架构实现SQL数据库是一个很好的解决方案。一个SQL数据库是可扩展、易管理,云就绪、高度可用的,完全建立在NoSQL的基础结构(分布式)上,但仍然提供SQL数据库的所有优势,如互操作性,定义良好的语义以及更多。

这种混合结构也许不如纯粹的NoSQL的服务,但足以满足需要更稳定系统、可扩展性和云服务的80%的市场需求。

这种解决办法还允许很容易地迁移现有的应用到云环境,从而保护相关组织在这些应用上所付出的巨大的投资。

在我看来,构建于NoSQL基础之上的SQL数据库,可以为那些在其成长期间期望灵活、高效的客户提供最高的价值。

NoSQL架构实践(一)——以NoSQL为辅

怎么样把NoSQL引入到我们的系统架构设计中,需要根据我们系统的业务场景来分析,什么样类型的数据适合存储在NoSQL数据库中,什么样类型的数据必须使用关系数据库存储。明确引入的NoSQL数据库带给系统的作用,它能解决什么问题,以及可能带来的新的问题。下面我们分析几种常见的NoSQL架构。

(一)NoSQL作为镜像

不改变原有的以MySQL作为存储的架构,使用NoSQL作为辅助镜像存储,用NoSQL的优势辅助提升性能。

图 1 -NoSQL为镜像(代码完成模式 )

//写入数据的示例伪代码 //data为我们要存储的数据对象 data.title=”title”; data.name=”name”; data.time=”2009-12-01 10:10:01”; data.from=”1”; id=DB.Insert(data);//写入MySQL数据库 NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库

如果有数据一致性要求,可以像如下的方式使用

//写入数据的示例伪代码 //data为我们要存储的数据对象 bool status=false; DB.startTransaction();//开始事务 id=DB.Insert(data);//写入MySQL数据库 if(id>0){ status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库 } if(id>0 && status==true){ DB.commit();//提交事务 }else{ DB.rollback();//不成功,进行回滚 }

上面的代码看起来可能觉得有点麻烦,但是只需要在DB类或者ORM层做一个统一的封装,就能实现重用了,其他代码都不用做任何的修改。

这种架构在原有基于MySQL数据库的架构上增加了一层辅助的NoSQL存储,代码量不大,技术难度小,却在可扩展性和性能上起到了非常大的作用。只需要程序在写入MySQL数据库后,同时写入到NoSQL数据库,让MySQL和NoSQL拥有相同的镜像数据,在某些可以根据主键查询的地方,使用高效的NoSQL数据库查询,这样就节省了MySQL的查询,用NoSQL的高性能来抵挡这些查询。

图 2 -NoSQL为镜像(同步模式)

这种不通过程序代码,而是通过MySQL把数据同步到NoSQL中,这种模式是上面一种的变体,是一种对写入透明但是具有更高技术难度一种模式。这种模式适用于现有的比较复杂的老系统,通过修改代码不易实现,可能引起新的问题。同时也适用于需要把数据同步到多种类型的存储中。

MySQL到NoSQL同步的实现可以使用MySQL UDF函数,MySQL binlog的解析来实现。可以利用现有的开源项目来实现,比如:

  • MySQL memcached UDFs:从通过UDF操作Memcached协议。
  • 国内张宴开源的mysql-udf-http:通过UDF操作http协议。

有了这两个MySQL UDF函数库,我们就能通过MySQL透明的处理Memcached或者Http协议,这样只要有兼容Memcached或者Http协议的NoSQL数据库,那么我们就能通过MySQL去操作以进行同步数据。再结合lib_mysqludf_json,通过UDF和MySQL触发器功能的结合,就可以实现数据的自动同步。

(二)MySQL和NoSQL组合

MySQL中只存储需要查询的小字段,NoSQL存储所有数据。

图 3 -MySQL和NoSQL组合

//写入数据的示例伪代码 //data为我们要存储的数据对象 data.title=”title”; data.name=”name”; data.time=”2009-12-01 10:10:01”; data.from=”1”; bool status=false; DB.startTransaction();//开始事务 id=DB.Insert(“INSERT INTO table (from) VALUES(data.from)”);//写入MySQL数据库,只写from需要where查询的字段 if(id>0){ status=NoSQL.Add(id,data);//以写入MySQL产生的自增id为主键写入NoSQL数据库 } if(id>0 && status==true){ DB.commit();//提交事务 }else{ DB.rollback();//不成功,进行回滚 }

把需要查询的字段,一般都是数字,时间等类型的小字段存储于MySQL中,根据查询建立相应的索引,其他不需要的字段,包括大文本字段都存储在NoSQL中。在查询的时候,我们先从MySQL中查询出数据的主键,然后从NoSQL中直接取出对应的数据即可。

这种架构模式把MySQL和NoSQL的作用进行了融合,各司其职,让MySQL专门负责处理擅长的关系存储,NoSQL作为数据的存储。它有以下优点:

  • 节省MySQL的IO开销。由于MySQL只存储需要查询的小字段,不再负责存储大文本字段,这样就可以节省MySQL存储的空间开销,从而节省MySQL的磁盘IO。我们曾经通过这种优化,把MySQL一个40G的表缩减到几百M。
  • 提高MySQl Query Cache缓存命中率。我们知道query cache缓存失效是表级的,在MySQL表一旦被更新就会失效,经过这种字段的分离,更新的字段如果不是存储在MySQL中,那么对query cache就没有任何影响。而NoSQL的Cache往往都是行级别的,只对更新的记录的缓存失效。
  • 提升MySQL主从同步效率。由于MySQL存储空间的减小,同步的数据记录也减小了,而部分数据的更新落在NoSQL而不是MySQL,这样也减少了MySQL数据需要同步的次数。
  • 提高MySQL数据备份和恢复的速度。由于MySQL数据库存储的数据的减小,很容易看到数据备份和恢复的速度也将极大的提高。
  • 比以前更容易扩展。NoSQL天生就容易扩展。经过这种优化,MySQL性能也得到提高。
MySQL与NoSQL——SQL与NoSQL的融合

写这一篇内容的原因是MySQL5.6.2突然推出了memcached的功能。NoSQL to InnoDB with Memcached的出现,可以看出NoSQL对关系数据库的确产生了巨大的影响,个人觉得这是一个非常大的进步,可以让开发人员更加方便的使用NoSQL和关系数据库。NoSQL一般被认为性能高于关系数据库,那么直接在InnoDB之上提供NoSQL功能并和MySQL共存是否是一个更好的选择呢?

MySQL withHandlerSocket

去年在twitter上看到HandlerSocket的出现,并宣称性能是Memcached的两倍时,非常令人吃惊,居然可以达到750000qps。接着HandlerSocket成为NoSQL领域谈论的焦点之一, 大量的人开始想要尝试,并做过一些自己的性能测试。 下图是HandlerSocket的结构图:

图1 HandlerSocket结构图(来源于官方)

HandlerSocket的出现,给我们眼前一亮的感觉。原来InnoDB的性能已经足够好,并可以直接提供NoSQL的功能。最大的好处就是可以共享MySQL的功能,DBA以前的经验一样可以用。但是有些小小的风险:

•HandlerSocket没有与MySQL一起发布版本,因此对于使用MyISAM引擎的用户是无缘的。不过现在Percona-Server已经集成了HandlerSocket,可以非常方便的使用。

•目前大规模的成功案例并不多,国内也只有少部分公司在尝试,我知道的有飞信开放平台,据说还不错。

•官方给出的测试数据在应用场景上其实并不充分,至少测试的场景跟我们实际使用的场景相差很大。但是毫无疑问, HandlerSocket的性能比直接使用MySQL肯定要高效得多。

InnoDB with Memcached

也许是因为HandlerSocket的火爆的冲击,也许是受HandlerSocket的启发,MySQL开始关注NoSQL领域的应用,并在MySQL5.6.2版本增加了通过Memcached协议直接访问原生Innodb API的功能。

InnoDB with Memcached是在提供MySQL服务的同一进程中提供Memcached服务 ,这与HandlerSocket的架构模式几乎是一样的。虽然目前InnoDB with Memcached还是预览版本,但是我个人更看好它,因为:

•它使用Memcached协议,并同时支持文本和二进制协议,在client的选择和成熟度上就要胜出许多;

•其支持的三种cache模式,不但可以省去开发中使用Memcached来缓存数据的麻烦,并且具有更好的可靠性和数据一致性;

•在应用程序中,可以使用高效的memcached协议来操作数据,同时也可以使用sql进行复杂的查询操作;

注意:目前通过memcached的更新操作不会记录到binlog中,未来的版本会支持。

图二 InnoDB withMemcached

Memcached and MySQLCluster

显而易见,我们会想到MySQL Cluster结合Memcached是一个更好的组合,MySQL Cluster提供了99.999%高可用性,并真正提供了去中心化的无缝高可扩展性。还有什么比这更人兴奋的呢。

MySQL已经提供了这样的功能,源代码在这里。这里有一个O'Reilly MySqlConference大会的PPT演示 ,你也可以看下这个功能开发者的一篇博客。

图三 NDB with Memcached

MySQL Cluster虽然具有高可靠性和无缝扩展的优势,但是对于复杂SQL查询的效率却不能令人满意。不过对于仅仅依赖于key-value查询和写入的海量数据存储需求,MySQL Cluster with Memcached应该是个很好的选择。

总结

Memcached协议由于其简单、协议轻量、存在大量的client,所以提供兼容Memcached协议的产品比较占据先天的优势。

MySQL提供NoSQL的功能,个人觉得并不是MySQL耐不住寂寞,而是的确在响应用户的需求。我前面的文章也说过,“NoSQL只是一个概念,并不是一个数据库 产品,MySQL也可以是NoSQL”,现在也正应了这句话。NoSQL从架构上就约束了开发者的架构和开发方式,从而提高扩展性和性能,而NoSQL和MySQL的融合,也同时提供了复杂查询功能。

虽然MySQL提供了NoSQL功能,如果你要尝试的话,你的数据库设计必须从NoSQL从发,然后再考虑SQL查询功能。

SQL与NoSQL的融合的确会给开发者带来方便,比如最近很流行的Mongodb,它吸引开发最大的点就是支持简单的关系查询。SQL与NoSQL的融合可能是未来很多数据库产品的一个趋势。但是纯NoSQL数据库的优势也是显著的,就是他的简单、高效、易扩展。

 

解读NoSQL技术代表之作Dynamo NoSQL背后的两种模式

NoSQL其实并不是什么妖魔鬼怪,相反,NoSQL的真谛其实应该是Not Only SQL,其产生背景是在数据量和访问量逐渐增大的情况下下,人为地去添加机器或者切分数据到不同的机器,变得越来越困难,人力成本越来越高,于是便开始有了这样的项目,它们的本意是提高数据存储的自动化程度,减少人为干预的时间,让负载更加均匀等。在国际上,真正的代表之作有来自Google的 BigTable 和Amazon的Dynamo,他们分别使用了不同的基本原理。

MapReduce

这是历史最久的一种模型,典型的代表是BigTable。Map表示映射,Reduce表示化简。MapReduce通过把对数据集的大规模操作分发给网络上的每个节点实现可靠性(Map);每个节点会周期性地把完成的工作和状态的更新报告回来(Reduce)。大多数分布式运算可以抽象为MapReduce操作。Map是把输入Input分解成中间的Key/Value对,Reduce把Key/Value合成最终输出Output。这两个函数由程序员提供给系统,下层设施把Map和Reduce操作分布在集群上运行。

Dynamo

这里我把Dynamo专门归纳成为了一种,其原因是它与MapReduce有很大的不同,自成一派。先说一下历史,Amazon于2006年推出了自己的云存储服务S3,2007年其CTO公布了S3的设计方案,从此江湖中就不再太平了,开源项目一个个如雨后春笋般地出现了。比较常见的有Facebook开发的Cassandra(如果没有记错,在去年浏览他们项目网页的时候,上面还写着他们之中的一个开发人员是Dynamo的设计人员,现在风头紧,去掉了),还有Linkedin的voldemort,而在国内话,有豆瓣网的beansDB,人人网的nuclear等等。这里我主要讨论的也是Dynamo的方案细节。

入门基础

Dynamo的意思是发电机,顾名思义,这一整套的方案都像发电机一样,源源不断地提供服务,永不间断。以下内容看上去有点教条,但基本上如果你要理解原理,这每一项都是必须知道的。

CAP原则

先来看历史,Eric A. Brewer教授,Inktomi公司的创始人,也是berkeley大学的计算机教授,Inktomi是雅虎搜索现在的台端技术核心支持。最主要的是,他们(Inktomi公司)在最早的时间里,开始研究分布计算。CAP原则的提出,可以追溯到2000年的时候(可以想象有多么早!),Brewer教授在一次谈话中,基于他运作Inktomi以及在伯克利大学里的经验,总结出了CAP原则(文末参考资料中有其演讲资料链接)。图一是来自Brewer教授当年所画的图:

图一:CAP原则当年的PPT

Consistency(一致性):即数据一致性,简单的说,就是数据复制到了N台机器,如果有更新,要N机器的数据是一起更新的。 Availability(可用性):好的响应性能,此项意思主要就是速度。 Partition tolerance(分区容错性):这里是说好的分区方法,体现具体一点,简单地可理解为是节点的可扩展性。

定理:任何分布式系统只可同时满足二点,没法三者兼顾。 忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

DHT——分布式哈希表

DHT(Distributed Hash Table,分布式哈希表),它是一种分布式存储寻址方法的统称。就像普通的哈希表,里面保存了key与value的对应关系,一般都能根据一个key去对应到相应的节点,从而得到相对应的value。

这里随带一提,在DHT算法中,一致性哈希作为第一个实用的算法,在大多数系统中都使用了它。一致性哈希基本解决了在P2P环境中最为关键的问题——如何在动态的网络拓扑中分布存储和路由。每个节点仅需维护少量相邻节点的信息,并且在节点加入/退出系统时,仅有相关的少量节点参与到拓扑的维护中。至于一致性哈希的细节就不在这里详细说了,要指明的一点是,在Dynamo的数据分区方式之后,其实内部已然是一个对一致性哈希的改造了。

进入Dynamo的世界

有了上面一章里的两个基础介绍之后,我们开始进入Dynamo的世界。

Dynamo的数据分区与作用

在Dynamo的实现中提到一个关键的东西,就是数据分区。 假设我们的数据的key的范围是0到2的64次方(不用怀疑你的数据量会超过它,正常甚至变态情况下你都是超不过的,甚至像伏地魔等其他类Dynamo系统是使用的 2的32次方),然后设置一个常数,比如说1000,将我们的key的范围分成1000份。然后再将这1000份key的范围均匀分配到所有的节点(s个节点),这样每个节点负责的分区数就是1000/s份分区。

如图二,假设我们有A、B、C三台机器,然后将我们的分区定义了12个。

图二:三个节点分12个区的数据的情况

因为数据是均匀离散到这个环上的(有人开始会认为数据的key是从1、2、3、4……这样子一直下去的,其实不是的,哈希计算出来的值,都是一个离散的结果),所以我们每个分区的数据量是大致相等的。从图上我们可以得出,每台机器都分到了三个分区里的数据,并且因为分区是均匀的,在分区数量是相当大的时候,数据的分布会更加的均匀,与此同时,负载也被均匀地分开了(当然了,如果硬要说你的负载还是只集中在一个分区里,那就不是在这里要讨论的问题了,有可能是你的哈希函数是不是有什么样的问题了)。

为什么要进行这样的分布呢,分布的好处在于,在有新机器加入的时候,只需要替换原有分区即可,如图三所示:

图三:加入一个新的节点D的情况

同样是图二里的情况,12个分区分到ABC三个节点,图三中就是再进入了一个新的节点D,从图上的重新分布情况可以得出,所有节点里只需要转移四分之一的数据到新来的节点即可,同时,新节点的负载也伴随分区的转移而转移了(这里的12个分区太少了,如果是1200个分区甚至是12000个分区的话,这个结论就是正确的了,12个分区只为演示用)。

从Dynamo的NRW看CAP法则

在Dynamo系统中,第一次提出来了NRW的方法。 N:复制的次数; R:读数据的最小节点数; W:写成功的最小分区数。 这三个数的具体作用是用来灵活地调整Dynamo系统的可用性与一致性。

举个例子来说,如果R=1的话,表示最少只需要去一个节点读数据即可,读到即返回,这时是可用性是很高的,但并不能保证数据的一致性,如果说W同时为1的 话,那可用性更新是最高的一种情况,但这时完全不能保障数据的一致性,因为在可供复制的N个节点里,只需要写成功一次就返回了,也就意味着,有可能在读的这一次并没有真正读到需要的数据(一致性相当的不好)。如果W=R=N=3的话,也就是说,每次写的时候,都保证所有要复制的点都写成功,读的时候也是都读到,这样子读出来的数据一定是正确的,但是其性能大打折扣,也就是说,数据的一致性非常的高,但系统的可用性却非常低了。如果R + W > N能够保证我们“读我们所写”,Dynamo推荐使用322的组合。

Dynamo系统的数据分区让整个网络的可扩展性其实是一个固定值(你分了多少区,实际上网络里扩展节点的上限就是这个数),通过NRW来达到另外两个方 向上的调整。

Dynamo的一些增加可用性的补救

针对一些经常可能出现的问题,Dynamo还提供了一些解决的方法。

第一个是hinted handoff数据的加入:在一个节点出现临时性故障时,数据会自动进入列表中的下一个节点进行写操作,并标记为handoff数据,在收到通知需要原节点恢复时重新把数据推回去。这能使系统的写入成功大大提升。

第二个是向量时钟来做版本控制:用一个向量(比如说[a,1]表示这个数据在a节点第一次写入)来标记数据的版本,这样在有版本冲突的时候,可以追溯到出现问题的地方。这可以使数据的最终一致成为可能。(Cassandra未用vector clock,而只用client timestamps也达到了同样效果。)

第三个是Merkle tree来提速数据变动时的查找:使用Merkle tree为数据建立索引,只要任意数据有变动,都将快速反馈出来。

第四个是Gossip协议:一种通讯协议,目标是让节点与节点之间通信,省略中心节点的存在,使网络达到去中心化。提高系统的可用性。

后记

Dynamo的理论对CAP原则里的可扩展性做到了很方便的实现,通过创造性的NRW来平衡系统的可用性和一致性,增加了系统在实际情况下遇到问题的可选择方案。可以相像,在NoSQL的道路上,这只是个开端,在分布式计算的道路上,已经是MapReduce之后的再次革命。

企业中的NoSQL 什么是NoSQL——快速回顾

像许多关注这一领域的人一样,我不喜欢从本质上将SQL与NoSQL这一术语对立起来。同时我对该术语现有的解释"Not Only SQL"也不甚满意。对我来说,我们这里所讨论的并非是是否使用SQL。(相反的是,我们仍然可以选择类似SQL这样的查询接口(缺少对join等的支持)来与这些数据库交互,使用现有的资源和技术来管理开发伸缩性和可维护性。) 这一运动是要找到存储和检索数据的其他高效的途径,而不是盲目地在任何情况下都把关系数据库当作万金油。因此,我认为'Non Relational Database'(非关系型数据库)能够更好的表达这一思想。

无论采用哪个名字,“非关系型数据库”这一范围所传达出来的“囊括所有”类型的意味,使得这一概念比较模糊(并且它还是否定型的)。这又使得人们(特别是企业中的决策者)对于哪些是属于这个范围,哪些不是,更重要的是,对他们来说这到底意味着什么,感到非常迷惑。

为了解答这些疑问,我尝试通过以下几点特征的描述,来刻画“非关系型数据库”的内在本质。

所谓“非关系型数据库”指的是

  1. 使用松耦合类型、可扩展的数据模式来对数据进行逻辑建模(Map,列,文档,图表等),而不是使用固定的关系模式元组来构建数据模型。
  2. 以遵循于CAP定理(能保证在一致性,可用性和分区容忍性三者中中达到任意两个)的跨多节点数据分布模型而设计,支持水平伸缩。这意味着对于多数据中心和动态供应(在生产集群中透明地加入/删除节点)的必要支持,也即弹性(Elasticity)。
  3. 拥有在磁盘或内存中,或者在这两者中都有的,对数据持久化的能力,有时候还可以使用可热插拔的定制存储。
  4. 支持多种的'Non-SQL'接口(通常多于一种)来进行数据访问。

围绕着图中四个特征的(数据持久性、逻辑数据模型、数据分布模型和接口)“非关系型数据库”的各种变形,在最近的一些文章中有详尽的描述,并且在因特网上有着广泛的传播。所以我就不做过多繁复的描述,而是通过一些例子对关键的方向进行总结,供快速参考:

接口——REST (HBase,CouchDB,Riak等),MapReduce(HBase,CouchDB,MongoDB,Hypertable等),Get/Put(Voldemort,Scalaris等),Thrift (HBase,Hypertable,Cassandra等),语言特定的API(MongoDB)。

逻辑数据模型——面向键值对的(Voldemort,Dynomite等),面向Column Family的(BigTable,HBase,Hypertable等),面向文档的(Couch DB,MongoDB等),面向图的(Neo4j, Infogrid等)

数据分布模型——一致性和可用性(HBase,Hypertable, MongoDB等), 可用性和可分区性(Cassandra等)。一致性和可分区性的组合会导致一些非额定的节点产生可用性的损失。有趣的是目前还没有一个“非关系型数据库”支持这一组合。

数据持久性——基于内存的(如Redis,Scalaris, Terrastore),基于磁盘的(如MongoDB,Riak等),或内存及磁盘二者的结合(如HBase,Hypertable,Cassandra)。存储的类型有助于我们辨别该解决方案适用于哪种类型。然而,在大多数情况下人们发现基于组合方案的解决方案是最佳的选择。既能通过内存数据存储支持高性能,又能在写入足够多的数据后存储到磁盘来保证持续性。

如何将其与企业IT融合

如今的企业中,并非所有用例都直观地倾向于使用关系型数据库,或者都需要严格的ACID属性(特别是一致性和隔离性)。在80年代及90年代,绝大部分存储在企业数据库里的数据都是结构化的业务事务的“记录”,必须用受控的方式来生成或访问,而如今它已一去不复返了。无可争辩的是,仍有这一类型的数据在那里,并将继续也应该通过关系型数据库来建模,存储和访问。但对于过去15年以来,随着Web的发展,电子商务和社交计算的兴起所引起的企业里不受控的非结构化并且面向信息的数据大爆炸,该如何应对呢?企业确实不需要关系型数据库来管理这些数据,因为关系型数据库的特点决定了它不适用于这些数据的性质和使用方式。

上图总结了现今以web为中心的企业中信息管理的新兴模式。而“非关系型数据库” 是处理这些趋势的最佳选择(较之关系型数据库来说),提供了对非结构化数据的支持,拥有支持分区的水平伸缩性,支持高可用性等等。

以下是支持这一观点的一些实际应用场景:

日志挖掘——集群里的多个节点都会产生服务器日志、应用程序日志和用户活动日志等。对于解决生产环境中的问题,日志挖掘工具非常有用,它能访问跨服务器的日志记录,将它们关联起来并进行分析。使用“非关系型数据库”来定制这样的解决方案将会非常容易。

分析社交计算——许多企业如今都为用户(内部用户、客户和合作伙伴)提供通过消息论坛,博客等方式来进行社交计算的能力。挖掘这些非结构化的数据对于获得用户的喜好偏向以及进一步提升服务有着至关重要的作用。使用“非关系型数据库” 可以很好的解决这一需求。

外部数据feed聚合——许多情况下企业需要消费来自合作伙伴的数据。显然,就算经过了多轮的讨论和协商,企业对于来自合作伙伴的数据的格式仍然没有发言权。同时,许多情况下,基于合作伙伴业务的变更,这些数据格式也频繁的发生变化。通过“非关系型数据库”来开发或定制一个ETL解决方案能够非常成功的解决这一问题。

高容量的EAI系统——许多企业的EAI系统都有高容量传输流(不管是基于产品的还是定制开发的)。出于可靠性和审计的目的,这些通过EAI系统的消息流通常都需要持久化。对于这一场景,“非关系型数据库” 再次体现出它十分适用于底层的数据存储,只要能给定环境中源系统和目标系统的数据结构更改和所需的容量。

前端订单处理系统——随着电子商务的膨胀,通过不同渠道流经零售商、银行和保险供应商、娱乐服务供应商、物流供应商等等的订单、应用、服务请求的容量十分巨大。同时,由于不同渠道的所关联的行为模式的限制,每种情况下系统所使用的信息结构都有所差异,需要加上不同的规则类型。在此之上,绝大部分数据不需要即时的处理和后端对帐。所需要的是,当终端用户想要从任何地方推送这些数据时,这些请求都能够被捕获并且不会被打断。随后,通常会有一个对帐系统将其更新到真正的后端源系统并更新终端用户的订单状态。这又是一个可以应用“非关系型数据库”的场景,可用于初期存储终端用户的输入。这一场景是体现“非关系型数据库”的应用的极佳例子,它具有高容量,异构的输入数据类型和对帐的"最终一致性"等等特点。

企业内容管理服务——出于各种各样的目的,内容管理在企业内部得到了广泛的应用,横跨多个不同的功能部门比如销售、市场、零售和人力资源等。企业大多数时间所面临的挑战是用一个公共的内容管理服务平台,将不同部门的需求整合到一起,而它们的元数据是各不相同的。这又是“非关系型数据库”发挥作用的地方。

合并和收购——企业在合并与收购中面临巨大的挑战,因为他们需要将适应于相同功能的系统整合起来。“非关系型数据库” 可解决这一问题,不管是快速地组成一个临时的公共数据存储,或者是架构一个未来的数据存储来调和合并的公司之间现有公共应用程序的结构。

但我们如何才能准确的描述,相对于传统的关系型数据库,企业使用“非关系型数据库”带来的好处呢?下面是可通过非关系型数据库的核心特点(正如上一节所讨论的)而获得的一些主要的好处,即企业的任何IT决策都会参考的核心参数——成本削减,更好的周转时间和更优良的质量。

业务灵活性——更短的周转时间

“非关系型数据库”能够以两种基本的方式带来业务灵活性。

  • 模式自由的逻辑数据模型有助于在为任何业务进行调整时带来更快的周转时间,把对现有应用和功能造成影响减到最少。在大多数情况下因任意的变更而给你带来的迁移工作几乎为零。
  • 水平伸缩性能够在当越来越多的用户负载造成负载周期性变化,或者应用突然变更的使用模式时,提供坚固的保障。面向水平伸缩性的架构也是迈向基于SLA构建(例如云)的第一步,这样才能保证在不断变化的使用情形下业务的延续性。
更佳的终端用户体验——更优越的质量

在现今企业IT中,应用的质量主要由终端用户的满意度来决定。“非关系型数据库”通过解决如下终端用户的考虑因素,能够达到同样的效果,而这些因素也是最容易发生和最难以处理的。

  • “非关系型数据库” 为提升应用的性能带来了极大的机会。分布式数据的核心概念是保证磁盘I/O(寻道速率)绝不能成为应用性能的瓶颈。尽管性能更多的是由传输速率来决定。在此之上,绝大部分解决方案支持各种不同的新一代的高速计算的范式,比如MapReduce,排序列,Bloom Filter,仅可追加的B树,Memtable等。
  • 现今用户满意度的另一个重要的方面就是可靠性。终端用户希望在想要访问应用时就能访问到,并且至少是在当他们分配到时间的时候能随时执行他们的任务。所以不可用的应用需要不惜代价的避免。许多现代的“非关系型数据库”都能适应并支持这一类有着严格和最终一致性的可用性的需求。
更低的所有者总成本

在如今的竞争市场中,企业IT支出随时都要仔细审查,以合理的成本获取合理的质量才值得赞许。在这一领域中“非关系型数据库”在一定程度上胜于传统的数据库,特别是当存储和处理的数据容量很大时。

  • 水平伸缩性的基本前提保证了它们可以运行于廉价机器之上。这不仅削减了硬件资本的成本,同时还削减了诸如电力,维护等运维成本。同时这还进一步的为利用诸如云、虚拟数据中心等下一代低成本的基础设施打下了基础。
  • 从长期来看,更少的维护能带来更多的运维成本优势。对于关系型数据库,这绝对是一个需要存储大容量数据的场景。为大容量的数据调优数据库需要高超的技艺,也就意味着更高的成本。相较之下,“非关系型数据库”始终提供快速和响应的特点,就算是在数据大幅上升的情况下。索引和缓存也以同样的方式工作。开发者不必过多担心硬件、磁盘、重新索引及文件布局等,而是把更多的精力投入了应用程序的开发上。
企业采用中所面临的挑战

抛开所有这些长远的好处,在企业拥抱“非关系型数据库”之前,当然还需要经历各种各样的挑战。

不考虑因现有思想的转换和缺乏信心而产生的来自高层的阻力,目前我认为的最主要的战术性挑战是:

为“非关系型数据库”认定正确的应用/使用场景

尽管从理论上容易论证并非所有的企业数据都需要基于关系和ACID的系统,然而由于关系型数据库与企业数据间多年的绑定关系,要作出所有的数据可以通过非关系的解决方案而解耦的决定仍然有很多困难。许多时候IT经理(以及其它对于应用程序负有核心的底线责任的各级人员)不明白他们将会失去什么,这样的担忧对于从关系型数据库转变出来比较不利。企业IT最有价值的资产就是数据。因此,要作出决定使用一种不太明确或者未被广泛采用的解决方案来管理同样的数据,这种能力不仅需要转换思维方式,同时还需要来自高层的强大的支持(和推动)。

我们如何选择最适合我们的产品/解决方案

另一个重大的挑战是找出合适的产品/工具来提供“非关系型数据库”。正如前面所提到的那样,现今业界里面有多于25种不同的产品和解决方案,它们在四个方面有着不同的特点。正因为每个产品在这四个方面特点各异,所以要选择一个产品来应对所有的需求显得尤为困难。有的时候,可能在企业的不同部门使用到多种类型的非关系型数据库,最后人们可能会完全出于对标准的需要而转向关系型数据库。

如何获得规模经济

这一想法本质上是从前一个问题分支出来的。如果一个组织需要使用多个非关系型数据库解决方案(由于单个方案的适用问题),那么保证在技术(开发者,管理者,支持人员),基础设施(硬件成本,软件许可成本,支持成本,咨询成本),以及工件(公共组件和服务)方面的规模经济就是一个大问题。这一方面与传统的关系型数据库解决方案比较起来确实更为严峻,因为大部分时间组织的数据存储都是以共享服务的模式在运行的。

我们如何保证解决方案的可移植性

从“非关系型数据库”的发展来看,我们可以很直观地推测在未来的几年中这一领域会有许多变化,比如供应商的合并,功能的进步以及标准化。所以对于企业来说一个更好的策略是不要把宝押在某个特定的产品/解决方案上,以后才可以更灵活的转换到一个更好的经过考验的产品。 由于现在的非关系型产品/解决方案大部分是私有的,因此IT决策者在考虑尝试“非关系型数据库”之前,不得不认真考虑可移植性这一重要的问题。这纯粹是出于保护现有投资的需要。

我们如何获得合适的产品支持类型

现在的“非关系型数据库”能通过外部组织而提供支持方案的少之又少。就算有,也无法与Oracle,IBM或者微软等相比。特别是在数据恢复,备份和特定的数据恢复方面,由于许多“非关系型数据库”在这些方面未能提供一个健壮而易于使用的机制,对于企业决策者来说,仍存在很大的问题。

我们如何预算整体成本

与重量级的关系型数据库相比,“非关系型数据库”通常在性能和伸缩性特征方面能提供的数据更少。我也没有发现有TPC基准程序方面和类似的其它方面的数据。这将企业决策者置于了一个“没有方向”的情况下,因为他们不知道需要在硬件、软件许可、基础设施管理和支持等方面支出多大的费用。要得出一个预算估计,缺乏判断的数据就成了一个主要的障碍。因此在项目启动阶段,大部分情况下决策者还是会选择基于熟悉的关系型数据库的解决方案。

有时候,就算可以得到这些数字,但也不足以用来形成TCO模型并与传统的基于关系型数据库的数据存储和非关系型数据存储进行整体的成本分析(Capex+Opex)比较。通常情况下水平伸缩性所要求的大量的硬件机器(以及软件许可成本,支持成本),如果与垂直伸缩性乍一比较,会让人觉得战战兢兢,除非由此带来的好处经过基于TCO模型的全方位比较仍然被证明是可以持续的。

关于如何采用NoSQL的两点思考

这是否意味着目前来看企业应该对NoSQL运动持观望的态度呢?并非如此。诚然,“非关系型数据库”对于广泛的采用来说还未到完全成熟的阶段。但“非关系型数据库”作为未来企业骨架的潜力仍不能忽视。特别是不远的将来企业将更多地处理大容量的半结构化/非结构化以及最终一致性的数据,而不是相对而言小容量的,严格结构化的遵循ACID的数据。 所以现在而言至关重要的是做企业的关键决策人的思想工作,让他们明白企业的数据处理需要使用“非关系型数据库”。在这一过程中,要采取一些渐进的步骤把“非关系型数据库”应用到企业IT的一些关键的方面(技术,人员和流程),并产生一定的价值。这样,就可以用一种缓慢而稳健的方式从整体上来解决我们之前所总结出来的一系列问题。

采用一个产品/解决方案

如今市场上的选择非常多样化,可根据“非关系型数据库”侧重的面不同而进行差异化的处理。与此同时,企业应用场景可能需要不同类型的特点。然而以不同的解决方案来处理不同的应用/使用场景从规模经济的角度出发对于企业是不适宜的。因此最好是根据目标应用的需要最终落实到某一个具体的产品/解决方案上。需要注意的是大多数的解决方案在特性上都会有一些折中,有些特性可能在其它的产品中可以获得,有些可能只是在发展路线图当中暂时设定了一个位置。因为大部分的产品会在不久的将来不断趋于成熟,因此可以通过不同配置来提供不同的解决方案。所以只要现有的解决方案能适合目前大部分的需要,不妨作为一个起点将其采纳。

选择产品/解决方案的经验法则

  • 支持所需要的逻辑数据模型应当被给予更高的权重。这将从实质上决定该解决方案在当前或未来能否灵活地适应不同的业务需求。
  • 调查该产品所支持的物理数据模型的合适与否,据此对这一解决方案所需要的水平伸缩性、可靠性、一致性和分区性作出合理的评估。这同样能表明备份和恢复机制的可能性。
  • 接口支持需要与企业标准的运行环境对齐。由于这些产品支持多样的接口,所以这一点可以得到很好的处理。
  • 只要产品支持水平伸缩性,对于持久化模型的选择就不再重要了。

这里有一份一系列“非关系型数据库”的对照表。对于现在正认真考虑采用的企业来说,这是一个不错的起点。为了更贴近企业本身的情况,从25+的集合中挑选出的子集所用到的的关键选择标准是:

  1. 最重要的一点首先是企业应用程序必须支持有一定复杂程度的数据结构。否则的话,应用程序管理复杂性的责任将变得非常大。我认为比较合理的应当是介于纯粹的键值对与关系型模式中间的一种方案。出于这方面的考虑像Vlodemort,Tokyo Cabinet等产品就排除在了我的列表之外。
  2. 第二点是以低成本的分片/分区为大容量数据提供水平支持。缺乏这样的支持就使得解决方案与任何关系型数据库无异了。因此像Neo4J(尽管他有丰富的基于图的模型),Redis,CouchDB等此时此刻就被过滤出我的列表之外了。
  3. 最后一条评判标准,在企业级推广之前我会考虑一定程度的商业支持。否则的话,一旦出现生产环境的问题,我该去找谁呢?出于这一点,我不得不将现在的一些明星产品排除在外,比如Cassandra(尽管有很大的可能不久的将来Rackspace或者Cloudera就会对其提供支持,因为它已经被用于一些生产环境里边了,比如Twitter,Digg,Facebook)。

有了这些过滤标准,我可以精简这一列表,符合目前企业可用的产品有MongoDB(下一版本就会提供shards支持),Riak,Hypertable和HBase。下面这个表格中总结了这四个产品的主要特性。一个企业可以基于自己具体的实际情况从中作出选择,找到最适合自己需要的特性。

特性

MongoDB

Riak

HyperTable

HBase

逻辑数据模型

富文档,并提供对内嵌文档的支持

富文档

列家族(Column Family)

列家族(Column Family)

CAP支持

CA

AP

CA

CA

动态添加删除节点

支持(很快在下一发布中就会加入)

支持

支持

支持

多DC支持

支持

不支持

支持

支持

接口

多种特定语言API(Java,Python,Perl,C#等)

HTTP之上的JSON

REST,Thrift,Java

C++,Thrift

持久化模型

磁盘

磁盘

内存加磁盘(可调的)

内存加磁盘(可调的)

相对性能

更优(C++编写)

最优(Erlang编写)

更优(C++编写)

优(Java编写)

商业支持

10gen.com

Basho Technologies

Hypertable Inc

Cloudera

数据访问抽象

为数据访问创建一个单独的抽象层对于“非关系型数据库”来说是必须的。它可以带来多方面的好处。首先,应用开发者可以与底层解决方案的细节完全隔离开来。这对于技术方面的伸缩性带来了好处。同时未来如果需要更改底层的解决方案也很方便。这也以一个标准的方式满足了多个应用的要求(即去掉了Join,Group by等复杂特性的SQL)。

为性能和伸缩性创建模型

不管选择怎样的解决方案,使用标准技术(比如排队网络模型,分层排队网络等)来对性能和伸缩性进行建模都是高度推荐的。它能够为基本的服务器规划、拓扑以及整体的软件许可证成本,管理运行等提供必要的数据。这将实质上成为所有预算计划的主要参考数据,并对作出决策提供帮助。

构建显式的冗余

要防止数据丢失,除了将数据复制到备份服务器上,没有其它的办法了。尽管许多非关系型数据库提供自动复制功能,但仍然存在主节点单点失效的风险。因此最好是使用次节点备份,并准备好用于数据恢复和自动数据修复的脚本。出于这样的目的,应当充分的了解目标解决方案的物理数据模型,找出可能的恢复机制备选方案,基于企业的整体需求和实践来对这些选项作出评估。

构建公共数据服务平台

就像公共共享服务的关系型数据库一样,也可以构建非关系型数据库的公共数据服务来促进规模经济效应,满足基础设施和支持的需要。这对于未来进一步演化和更改也有帮助。这可以作为愿望列表上的最终目标,通过中期或长期的努力来达到这一成熟水平。然而,初始阶段就设立这样的远景有助于在整个过程中作出正确的决策。

壮大企业的技术力量

每个组织都有一部分人对于学习新生的和非传统的事物充满热忱。成立这样的小组,并挑选人员(全职的或兼职的),密切关注这方面的动向,了解问题和挑战,进行前瞻性的思考,能够为使用这些技术的项目提供方向和帮助。同时,这个小组还可以为决策者澄清炒作的疑云,提供来自真实数据的观点。

建立与产品社区的关系

选择了产品之后,与产品社区建立起良好的关系对于双方的成功都有极大的好处。许多非关系型数据库目前都有十分活跃的社区,非常愿意相互帮助。企业与社区之间的良好合作能给大家带来一个双赢的局面。如能提前对问题和解决方案有了解,那么企业在对某些特性或版本作出决策时就能成竹在胸。反过来,企业又能对产品特性的路线图产生影响作用,这对他们自身和社区都是有利的。另一方面,社区也能从实际层次的问题中得到反馈,从而丰富和完善产品。来自大型企业的成功案例同样能让他们处于领先。

迭代前进

考虑到非关系型数据库相对的成熟度,风险最小的采用策略就是遵循迭代开发的方法论。构建公共数据服务平台和标准化数据访问抽象不可能是一蹴而就的。相反,通过迭代和面向重构的方式能更好的达到目标。运用不太成熟的技术进行转型的过程,中途改变解决方案也不会太意外的。与此同时,采用敏捷的方式来看待事物,能够帮助建立起一个能从管理和实现两方面不断吸引改进的开放态度。

然而,在这一问题上实现迭代,非常重要的一点是定义一个决策条件矩阵。比如操作指南(和例子),来判断一个应用的对象模型是否适合关系型或非关系的范围,对基础设施规划作出指导,列出必需的测试用例等等。

结束语

企业的非关系型数据库采用过程中最大的挑战就是转变决策者的思想观念——让他们相信并非所有的数据/对象都适合关系型数据库。 最能证明这一点就是选择合适的用例去尝试非关系型数据库,进而证实在合适的背景下,非关系型数据库是比关系型数据库更有效的解决方案。找到一些“非关键业务”(但能立竿见影的)适合于非关系型数据库的项目。这些项目的成功(甚至失败)都能有助于观念的改变。这也能有助于不断学习如何才能以一种不同的方式来更好的采用非关系型数据库。这些少儿学步般的尝试所作出的努力与投入都是值得的,如果企业想要在将来使用“非关系型数据库”来重塑其信息管理体系的话。

关于作者

Sourav Mazumder目前是InfoSys Technologies的首席技术架构师。他在信息技术领域有14年以上的经验。作为Infosys技术顾问团的主要成员,Sourav为Infosys在美国、欧洲、澳洲和日本的主要客户,提供保险、电信、银行、零售、安全、交通以及建筑、工程、施工等多个行业的服务。他曾参与Web项目的技术架构和路线图定义,SOA战略实施,国际战略定义,UI组件化,性能建模,伸缩性分析,非结构化数据管理等等。Sourav参考的Infosys自身的核心银行产品Finacle,也为他提供了丰富的产品开发经验。Sourav还曾参与开发Infosys的J2EE可重用框架,和定义Infosys在架构方面和开发定制应用方面的软件工程方法。Sourav的经历还包括在保证架构合规和开发项目的治理方面的工作。

Sourav是iCMG认证的软件架构师,同时也是TOGAF 8认证的执行者。Sourav最近在LISA伯克利全球化会议上发表了演讲。Sourav关于SOA的最新白皮书在社区里十分流行。

Sourav目前关注NoSQL,Web2.0,治理,性能建构和全球化。

SQL vs NoSQL:数据库并发写入性能比拼

最近听说了很多关于NoSQL的新闻,比如之前Sourceforge改用MongoDB,Digg改用Cassandra等等。再加上之前做数据库比较时有人推荐我mongodb,所以也搜索了一下NoSQL,觉得NoSQL可能真的是未来的趋势。

NoSQL vs SQL

传统SQL数据库为了实现ACID(atomicity,consistency, isolation, durability),往往需要频繁应用文件锁,这使得其在现代的web2.0应用中越来越捉襟见肘。现在SNS网站每一个点击都是一条/多条查询,对数据库写的并发要求非常之高,而传统数据库无法很好地应对这种需求。而仔细想来SNS中大部分需求并不要求ACID,比如Like/Unlike投票等等。

NoSQL吸取了教训,比如有些NoSQL采用了eventually consistency的概念,在没有Update操作一段时间后,数据库将最终是consistency的,显然这样的数据库将能更好的支持高并发读写。

SQL数据库是基于schema的,这对时时刻刻更新着的web2.0应用开发者来说是个噩梦:随时随地有新的应用出现,旧的数据库无法适应新的应用,只能不停地更新schema,或者做补丁表,如此一来要么schema越发混乱,要么就是数据库频繁升级而耗时耗力耗钱。

NoSQL一般就没有schema这种概念,大部分NoSQL都直接保存json类的Row,比如一个记录可以是{ id = 1, name = Bob, phone = 38492839 },这样扩展升级非常方便,比如需要地址信息直接加入 address=blahblah 即可。

传统SQL很难进行分布式应用,即使可以也往往代价高昂。而NoSQL则很好地解决了这个问题:他们一般都直接从分布式系统中吸取了Map/Reduce方法,从而很容易就可以处理规模急速增加的问题。

推荐robbin牛的NoSQL数据库探讨之一 - 为什么要用非关系数据库?一文,介绍了主流的一些NoSQL系统,还有这个站http://nosql-database.org/收集了基本上目前所有的NoSQL系统。

总结一下我对NoSQL的看法,NoSQL出现的目的就是为了解决高并发读写的问题,而高并发应用往往需要分布式的数据库来实现高性能和高可靠性,所以NoSQL的关键字就是concurrency和scalability。

我的瓶颈

我之前主要关注数据库的select性能也就是read性能,在读性能方面SQL数据库并没有明显的劣势,应该说纯粹高并发读的性能的话往往要优于NoSQL数据库,然而一旦涉及写,事情就不一样了。

我本来以为自己不会遇到大量写的问题,后来发现即使在simplecd这种简单的应用环境下也会产生大量的并发写:这就是爬VC用户评论的时候。事实上,sqlite3在处理这个问题上非常的力不从心,所以我产生了换个数据库的想法。

既然我是要求能高并发读写,干脆就不用SQL了,但是同时我也想测试一下其他SQL的写性能。

我的数据有180万条,总共350M,测试用了10个线程,每个线程做若干次100个数据的bulk写入,然后记录总共耗时。结果如下:

innodb: 15.19 myiasm: 14.34 pgsql: 23.41 sqlite3: 锁住了 sqlite3(单线程): 300+ mongodb: 3.82 couchdb: 90 couchdb(单线程):66

作为一个MySQL黑,看到这组测试数据我表示压力很大。在SQL数据库中,mysql意外地取得了最佳的成绩,好于pgsql,远好于sqlite。更令人意外的是myisam居然优于号称insert比较快的innodb。不管如何,对我的应用来说,用mysql保存评论数据是一个更为明智的选择。我对mysql彻底改观了,我宣布我是mysql半黑。以后select-intensive的应用我还是会选择sqlite,但是insert/update-intensive的应用我就会改用mysql了。

MongoDB和CouchDB同为NoSQL,表现却截然相反,MongoDB性能很高,CouchDB的并发性能我只能ORZ,这种性能实在太抱歉了。

NoSQL的碎碎念

其实我本来还打算测试cassandra的,可是cassandra用的是java,这首先让我眉头一皱,内存大户我养不起啊,其次看了cassandra的文档,立刻崩溃,这简直就是没有文档么。(BTW,CouchDB也好不到哪里去,我都是用python-couchdb然后help(couchdb.client)看用法的)

至于CouchDB,可能是因为采用http方式发送请求,所以并发性能糟糕的一塌糊涂,很怀疑它是否有存在的理由。

MongoDB是我用下来最讨人喜欢的一个NoSQL。不但文档丰富,使用简单,性能也非常好,它的Map/Reduce查询(很多NoSQL都有)让我惊叹,数据库可以非常简单地就扩大规模,完全不用理会什么分区分表之类繁琐的问题,可惜这方面我暂时没有需求。但是MongoDB有两大致命问题。

第一是删除锁定问题,当批量删除记录时,数据库还是会锁定不让读写。这意味着进行数据清理时会让网站应用失去响应。见locking problems

第二是内存占用问题,MongoDB用了操作系统的内存文件映射,这导致操作系统会把所有空闲内存都分配给MongoDB,当MongoDB有这个需要时。更可怕的是,MongoDB从来不主动释放已经霸占的内存,它只会滚雪球一样越滚越大,除非重启数据库。这样的上下文环境下,MongoDB只适合一台主机就一个数据库,而没有其他应用的环境,否则一会儿功夫MongoDB就会吃光内存,然后你都fork不出新进程,彻底悲剧。见memory limit

总之NoSQL虽然让我眼前一亮,可是目前尝试的一些产品都让人望而生畏,现在的NoSQL都把目光放在了巨型网站上,而没有一个小型的,可以在VPS里面应用的高性能NoSQL,令我有点失望。NoSQL尚未成熟,很期待它的将来发展,目前来说MySQL还是更好的选择。

 

谷歌Jeff Dean阐述分布式系统设计模式 分布式系统设计模式

1. 系统失败是很平常的事情:每年有1-5%的硬盘会报废,服务器每年会平均宕机两次,报废几率在2-4%几率。

2. 将一个大而复杂系统切分为多个服务:而且服务之间依赖尽可能的少,这样有助于测试,部署和小团队独立开发。例子:一个google的搜索会依赖100多个服务。吴注:需要一套机制来确保服务的fault-tolerant,不能让一个服务的成败影响全局。

3. 需要有ProtocolDescription Language:比如protocol buffers。吴注:这样能降低通信方面的代码量。

4. 有能力在开发之前,根据系统的设计来预测性能:在最下面有一些重要的数字。

5.在设计系统方面,不要想做的很全面,而是需要抓住重点。

6. 为了增量做设计,但不为无限做设计。比如:要为5-50倍的增量做设计,但超过1000倍了,就需要重写和重新设计了。

7. 使用备份请求来降低延迟:比如一个处理需要涉及1000台机器,通过备份请求这个机制来避免这个处理被一台慢机器延误。吴注:这个机制非常适合MapReduce。

8. 使用范围来分布数据,而不是Hash:因为这样在语义上比较简单,并且容易控制。吴注:在大多数情况下语义比性能更重要,不要为了20%的情况hardcode。

9. 灵活的系统,根据需求来伸缩:并且当需求上来的时候,关闭部分特性,比如:关闭拼写检查。

10. 一个接口,多个实现。

11. 加入足够的观察和调式钩子(hook)。

12. 1000台服务器只需单一Master:通过Master节点来统一指挥全部的行动,但客户端和Master节点的交互很少,以免Master节点Crash,优点是,在语义上面非常清晰,但伸缩性不是非常强,一般最多只能支持上千个节点。

13. 在一台机器上运行多个单位的服务:当一台机器宕机时,能缩短相应的恢复时间,并且支持细粒度的负载均衡,比如在BigTable中,一个Tablet服务器会运行多个Tablet。

ZooKeeper—分布式协同服务

1.概述

ZooKeeper[1]是hadoop的一个分布式协同服务,主要解决分布式应用程序中的局部失败问题,即网络操作过程中发送者与接收者之间无法明确发送操作是否正确无误。在分布式系统中,它能够提供:系统配置信息维护,命名,分布式同步等服务。著名的Hadoop分布式数据库HBase已经采用了ZooKeeper技术为其提供服务[2],如,ZK存储了HBase中的Region的寻址入口;实时监控Rgeion Server的状态,将Region Server上、下线实时通知给master。

Zookeeper非常简化暴漏一些简单的基本操作,可以将其想象为一个简单的文件系统提供读、写操作服务,此外,它还有预定(ordering)和通知(notification)服务。ZK的可靠性体现在ZK服务是一一个集群的方式提供服务,所以,分布式应用程序不会因为使用ZK服务器而导致单点失败问题,相反,很多分布式应用程序可以通过引入ZK来解决本身系统存在的单点问题,HBase就是这样做的。

2.ZooKeeper安装

        1.下载http://www.apache.org/dyn/closer.cgi/zookeeper/最新文档版本。

2.解压:% tar xzf zookeeper-x.y.z.tar.gz 。配置环境变量:ZOOKEEPER_INSTALL指向ZK的安装目录,在PATH中加入可执行文件目录。简单的办法是在/etc/profile里加入下面两行:

export ZOOKEEPER_INSTALL=/home/tom/zookeeper-x.y.z

export PATH=$PATH:$ZOOKEEPER_INSTALL/bin

ZK的配置文件conf/zoo.cfg三个变量:

        trickTime= 2000   //ZK的基本时间单位,单位微秒

        dataDir=/usr/tom/zookeeper        //数据目录,用于存放ZK的持久化信息

        clientPort=2181                //ZK的默认监听端口

        3.启动ZK:

                           %zkServer.sh start

         4.确认安装:

                           %echo ruok | nc localhost 2181

        如果返回信息是imok(“Iam ok ”)的话表明安装成功。

以上只是简单的单机情况的配置。关于在实际生成系统中的安装配置,后面将详细介绍。

 

分布式数据库的具体实现与对比分析

1.前言

随着传统的数据库、计算机网络和数字通信技术的快速发展,以数据分布存储和分布处理为主要特征的分布式数据库系统的研究和开发越来越受到人们的关注。如何在一个数据库系统中实现一个分布式数据库,在实现分布是数据库中采用何种策略以及有那些需要注意的问题,这一直是数据库研究和应用相关领域人员非常关心的问题。本文就在Microsoft SQL系列数据库系统中分布式数据的具体实现进行了阐述,并对相关问题进行深入的分析。

 

2.分布式数据库简介

分布式数据库系统是在集中式数据库系统的基础上发展起来的,由分布式数据库管理系统和分布式数据库组成,是数据库技术与计算机网络技术的产物。分布式数据库管理系统是具有管理分布数据库功能的计算机系统,分布式数据库则是一组逻辑上属同一系统,但物理上分布在计算机网络的不同结点的结构化数据的集合,由分布于计算机网络上的多个逻辑相关的数据库组成。网络中的每个结点(场地)具有独立处理的能力(称为本地自治),可执行局部应用,同时,每个结点通过网络通讯系统也能执行全局应用。所谓局部应用即仅对本结点的数据库执行某些应用。所谓全局应用(或分布应用)是指对两个以上结点的数据库执行某些应用。支持全局应用的系统才能称为分布式数据库系统。对用户来说,一个分布式数据库系统逻辑上看如同集中式数据库系统一样,用户可在任何一个场地执行全局应用。分布式数据库系统的特点是:

(1)物理分布性:分布式数据库系统中的数据不是存储在一个站点上,而是分散存储在由计算机网络联结起来的多个站点上。

(2)逻辑整体性:分布式数据库系统中的数据物理上是分散在各个站点中,但这些分散的数据逻辑上却是一个整体,它们被分布式数据库系统的所有用户(全局用户)共享,并由一个分布式数据库管理系统统一管理。

(3)站点自治性:站点自治性也称场地自治性,每个站点上的数据由本地的DBMS 管理,具有自治处理能力,完成本站点的局部应用。

分布式数据库系统适合于单位分散的部门,系统的结点可反映公司的逻辑组织,允许各部门将其常用数据存贮在本地,实施就地存放就地使用,降低通讯费用,并可提高响应速度。分布式数据库可将数据分布在多个结点上,增加适当的冗余,可提高系统的可靠性,只要一个数据库和网络可用,那么全局数据库可一部分可用。不会因一个数据库的故障而停止全部操作或引起性能瓶颈。故障恢复通常在单个结点上进行。结点可独立地升级软件。每个局部数据库存在一个数据字典。由于分布式数据库系统结构的特点,它和集中式数据库系统相比具有以下优点:

1) 可靠性高,个别场地发生故障,不致引起整个系统的瘫痪

2) 可扩展性,为扩展系统的处理能力提供了较好的途径。

3) 均衡负载,可避免临界瓶颈

目前,随着计算机体系结构和数据库技术的发展,分布式数据库系统技术已经有了长足发展。基于关系数据模型的分布式数据库技术在商业处理的应用方面已非常成功,如Oracle、MS SQL SERVER、Sybase、IBM DB2等数据库平台,其分布式处理技术能很好地满足大型数据库管理的需要,并能实现一定的分布式实时分析处理和数据更新,能够满足各种不同类型用户对不同数据库功能的要求。但不同的数据库产品在价格、性能、稳定性等方面有着不小的差异,在对分布式数据库理论的支持程度、分布式实现的具体方式也都有各自的特点,用户应当根据各自的实际情况选用合适的数据库产品。

 

3.分布式数据库的具体实现

3.1实现的理论准备

3.1.1实现流程

由于以上集中式数据库所不能替代的特点,分布式数据库的使用已经越来越成为当前数据库使用的主流。同时如何根据实际情况实现一个架构可靠、运行稳定的分布式数据库也成为许多数据库使用者所面临的问题。综合来讲,设计并实现一个分布式数据库主要有以下几个步骤:

1) 掌握分布式数据库的基本原理。

2) 根据需求和实际情况选取一种合适的分布式数据库系统。

3) 了解在该数据库系统中分布式数据库的实现方式。

4) 在系统中的具体实现。

本文已经就以上几点分别做了简单阐述。下面将集中探讨一下在MS SQL 2000数据库系统中实现分布式数据库的方式。

3.1.2 MS SQL 2000数据库简介

MS SQL 2000数据库系统是微软公司的主流数据库产品,其工作效率、稳定性等指标都非常出色,且在具有友好、简单的操作方式的同时,对分布式数据库的实现有着完整的理论支持。且对不同类型的分布式数据库应用需求都提出了完善的解决方案。所以对MS SQL 2000数据库中分布式数据库实现的掌握对分布式数据库的实际设计以及在其它数据库平台上的实现都有很大的参考作

3.1.3"复制"技术与分布式事务处理

设计一个分布式计算解决方案首先需要考虑的问题就是应用的完整性、复杂性、性能和可用性以及响应时间等,同时还需要考虑的是对于不同的应用需求是采用实时存取远程数据(分布式事务处理)还是采用延迟存取远程数据("复制")。

MS SQL 2000数据库中的分布式事务处理即通过事务处理机制采用实时数据存取,能够保证数据的一致性。是一种实时远程存取和实时更新数据的技术。这种技术可以保证应用的完整性并降低了应用的复杂性,但是如果系统存在网络存取速度很慢这样的问题,相应响应时间就会很慢。这是一种同步分发数据库技术。

"复制",顾名思义就是将数据库中的数据拷贝到不同物理地点的数据库中以支持分布式应用,它是整个分布式计算解决方案的一个重要组成部分。这里针对"复制"也存在同步"复制"和异步"复制"的问题。同步"复制",复制数据在任何时间在任何复制节点均保持一致。如果复制环境中的任何一个节点的复制数据发生了更新操作,这种变化会立刻反映到其他所有的复制节点。这种技术适用于那些对于实时性要求较高的商业应用中。异步"复制",所有复制节点的数据在一定时间内是不同步的。如果复制环境中的其中的一个节点的复制数据发生了更新操作,这种改变将在不同的事务中被传播和应用到其他所有复制节点。这些不同的事务间可以间隔几秒,几分种,几小时,也可以是几天之后。复制节点之间的数据是不同步的,但传播最终将保证所有复制节点间的数据一致。这是一种延迟远程存取和延迟传播对数据更新的技术,有很高的可用性和很短的响应时间,相比同步分发数据库技术就显得复杂一些,为了确保应用的完整性需要仔细考虑和设计。

对于实际的商业问题,必须权衡这两种技术的利弊最终选择最佳的解决方案,有些问题选用分布式事务处理比较适合,也有一些问题采用"复制"是比较好的解决方案,还有一些问题必须综合这两种技术。

3.1.4 "发行-分布-订阅"结构

MS SQL 2000数据库系统中分布式数据库的具体实现采用"发行-分布-订阅"结构。具体来讲就是将实现分布式数据的角色分为三种,即发行者、分布者、订阅者。这三中角色在数据的分布中其着不同的作用:

1) 发行者:是发行项目的集合。发行项目也就是数据库中表、存储过程或特定的行或列等我们要作为分布式数据的这部分内容。

2) 订阅者:从发行者上进行数据的订阅,即按照需求使用发行者上的数据更新自己本地的数据。其订阅方式包括推出式订阅(属于主动式发布,发行者主动将数据传送到订阅者处)、引进式订阅(属于被动式发布,即当订阅者需要更新数据时再向发行者请求进行更新)

3) 发布者:负责管理,将发行者上发行的数据安计划传送到订阅者处。

通过采用"发行-分布-订阅"结构,分布式数据库中每一个角色的功能更加明确。同时应该注意的是,三种角色指的是再分布式数据实现中所起到的作用,并不是指具体的计算机。同一台计算机可能扮演多种角色,即一台主机在分布式数据库中有可能即使发行者,也是订阅者,或者三种都是。

3.2 "复制"策略的选择

MS SQL 2000数据库采用的"复制"方式有快照复制(Snapshot Replication)、事务复制(transaction replication)和合并复制(merge replication)三种,三者都是按照实现制定的"复制"策略,在一定的时间,按照一定的规则进行一定数量发布内容的复制,三者的具体差别及特点如下:

1) 快照复制:在复制时将所有发布数据全部重新传送一遍。此方法的特点是具有周期性、进行批量复制处理、高延迟、高度自治。但由于一次传送数据较多,灵活性差,故不适宜大型数据库。但同时此方法不需持续监控,故代价较低。

2) 事务复制:属于增量复制,即在复制时仅复制增减或变更的内容,特点是低延迟、低度自治,适宜大型数据库。但此方法需要持续监控,故代价较高。另外,此方法复制的方式也可设置为即时更新。

3) 合并复制:复制时即根据发行者上的数据,也根据订阅者上来进行更新。此方法高度自治,在过程中使用使用触发器,但由于其自身的实现方式,故不能保证数据一致性

不同的"复制"策略适用于不同的分布式数据库实现要求,我们可以根据延迟、站点自治、事务一致性、数据更新冲突、"复制"发生的频率需求和网络特性的各方面的实际情况来决定使用那一种或那几种"复制"策略。

3.3 "复制"的实现

在决定好"复制"的策略后,要在系统中进行具体的实现。其主要步骤包括:

3.3.1调整、设定发行者和分布者

通过对预发布的数据的了解和对接受数据者的判断等,我们已经确定了"复制"的策略,这一步我们就需要确定"复制"发生的频率需求并根据网络特性,如拓扑结构、"复制"类型的影响、空间需求等对发行者的发行内容和分布者的分布策略进行具体的设置。

3.3.2设置订阅者

通过分布式数据的要求和订阅者特征决定订阅者的属性,如选择订阅方式是"推出式订阅"还是"引进式订阅"等,此属性为最重要的内容。然后进行其他订阅服务属性设置。

3.3.3 设定代理服务

分布式数据库中的代理服务是进行"复制"管理的核心,它是一种始终运行的服务,负责全部"复制"任务的控制和管理。这些服务中主要包括:快照代理、分布代理、日志代理和合并代理等。每一种"复制"方法都需要一种或集中代理服务的配合。

通过以上几部分内容的设置,我们就可以建立并运行起一个完整、可行的分布式数据库。但经管这个数据库能够正确的实现并运行,并不一定意味者其"复制"机制能够始终保持稳定并一直符合我们的要求,所以,我们还需要对"复制"服务进行有效的管理。这就包括使用服务器的"复制"服务监视工具来对"复制"服务的维护,并在"复制"服务发生故障时进行的问题解决。

 

4.MS SQL 2000数据库对异类数据库"复制"的支持

MS SQL 2000数据库可以与其他异类数据库实现数据直接"复制",包括Microsoft Access数据库、Oracle系列数据库、IBM DB2数据库以及其他支持 SQL Server ODBC接口标准的数据库。这些异类数据库可以通过"复制"代理直接连接起来,组成一个大的分布式数据库,自由进行分布式数据的"复制"处理。

 

5.小结

分布式数据库以其高度的可扩展性和可伸缩性,同时由于资源共享提高了系统的性价比,已经得到广泛的研究和应用。本文就在MS SQL 2000数据库中实现分布式数据库的策略与具体方式做了详细的分析。MS SQL 2000数据库是一款常用的数据库产品,其分布式数据功能针对各种实际情况都有着完善的解决方案。通过对其分布式数据库实现策略、方法和特点的学习,可以加深我们对分布式数据库理论的认识,加强我们通过具体途径,解决实际问题的能力。

 

 

Hadoop:Google分布式存储/计算/查询系统的开源实现

Google的伟大很大程度上得益于其强大的数据存储和计算能力,GFS和Bigtable使得其基本摆脱了昂贵的人力运维,并节省了机器资源;MapReduce使其可以很快看到各种搜索策略试验的效果。鉴于此,国内外出现了很多的模仿者,它们都是所谓的“高科技”企业,且往往还打上“云计算”的标签。从头到尾实现一套Google的存储/计算/查询系统是极其复杂的,也只有寥寥无几的几个巨头可以做到,Hadoop做为一种开源的简化实现,帮了很多科技公司的大忙。前些时候,Yahoo将Hadoop的创始人收于麾下,使得Hadoop完成华丽大转身,性能实现了一个飞跃式提升。   Hadoop主要包括HDFS(分布式文件系统,对应GFS),MapReduce(分布式计算系统)和HBase(分布式查询系统,对应Bigtable),其中以HDFS和MapReduce较为成熟。另外,Hadoop还包括一些辅助系统,如分布式锁服务ZooKeeper,对应GoogleChubby。这一套系统的设计目标如下:   1. 简化运维:在大规模集群中,机器宕机,网络异常,磁盘错都属于正常现象,因此错误检查,自动恢复是核心架构目标。Google的解决方案就已经做到了机器随时加入/离开集群。   2. 高吞吐量:高吞吐量和低延迟是两个矛盾的目标,Hadoop优先追求高吞吐量,设计和实现中采用了小操作合并,基于操作日志的更新等提高吞吐量的技术。   3. 节省机器成本:Hadoop鼓励部署时利用大容量的廉价机器(性价比高但是机器故障概率大),数据的存储和服务也分为HDFS和HBase两个层次,从而最大限制地利用机器资源。   4. 采用单Master的设计:单Master的设计极大地简化了系统的设计和实现,由此带来了机器规模限制和单点失效问题。对于机器规模问题,由于Hadoop是数据/计算密集型系统,而不是元数据密集型系统,单Master设计的单个集群可以支持成千上万台机器,对于现在的几乎所有应用都不成问题;而单点失效问题可以通过分布式锁服务或其它机制有效地解决。   Google的其它模仿者包括,Microsoftdyrad(模范GoogleMapReduce),Hypertable(HadoopHBase开发团队核心成员开始的一个开源项目,C++实现的Bigtable)。Google的解决方案不是万能的,然而相对我们普通人已经是几乎不可逾越了。Hadoop做为Google的这个模型的简化实现,有很多不足,这里先列出几点,以后将通过阅读Hadoop源代码和论文逐渐展开分析。Hadoop的几个明显缺点如下:   1. 采用Java实现。Java的IO处理虽然没有性能瓶颈,但是对于CPU密集型的任务是一个噩耗。这点可以通过对比HBase和Hypertable两个开源的Bigtable实现来做初步的验证。   2. 开源项目。开源本身是一柄双刃剑,它方便了大多数人,但是对于一个有一定规模的公司,项目发展方向的把握,技术保密,技术支持等都是采用Hadoop这种开源项目必须考虑的问题。另外,Hadoop作为一个比较新的项目,性能和稳定性的提升还需要一定时间。

 

 

Moosefs介绍

MooseFS是一种分布式文件系统,MooseFS文件系统结构包括以下四种角色:   1 管理服务器managingserver (master)   2 元数据日志服务器Metaloggerserver(Metalogger)   3 数据存储服务器data servers(chunkservers)   4 客户机挂载使用clientcomputers 各种角色作用:    1 管理服务器:负责各个数据存储服务器的管理,文件读写调度,文件空间回收以及恢复.多节点拷贝   2 元数据日志服务器: 负责备份master服务器的变化日志文件,文件类型为changelog_ml.*.mfs,以便于在master server出问题的时候接替其进行工作   3 数据存储服务器:负责连接管理服务器,听从管理服务器调度,提供存储空间,并为客户提供数据传输.   4 客户端: 通过fuse内核接口挂接远程管理服务器上所管理的数据存储服务器,.看起来共享的文件系统和本地unix文件系统使用一样的效果.吧。 1 Moosefs简介 1.1 角色构成   整个mfs共计四种角色:master、metalogger、chunk和client   1、master:只有一台。   2、metalogger:可以有多台。它负责定期从master下载metadata,并实时同步changelog。metadata和changelog的关系类似于sfrd里面基准和增量的关系。当master挂了的时候,metalogger利用下载下来的metadata和实时同步的changelog来恢复master挂掉时候的metadata。并且接管master的功能。   3、chunk:提供存储的服务器,可以有多台。这些服务器负责提供存储,它可以自由的启动和停止。在chunk启动后,会主动与master联系,master知道有多少chunk在网络中,并且会定期检查chunk的状态。   4、client:使用mfs的服务器,可以有多台。它需要运行mfsmount命令,将网络上的存储挂载到本地,看起来类似nfs。client就像读写本地磁盘那样读写mfsmount挂载的网络存储。

 

解读:基于Hadoop的大规模数据处理系统

2010年8月27日下午,由中国电子学会云计算专家委员会主办、CSDN承办的“高端云计算课程”在中关村软件园进行了免费的公开课程,公开课上座无虚席,原定几十人的教室,最终挤满了上百人。本次高端课程以“普及云计算,利用云计算,发展云计算”为基本原则,旨在为云计算领域培养和选拔更多更优秀的技术和管理人才奠定坚实的基础。

 在本次公开课上,中科院计算所副研究员查礼博士做了主题演讲,解密了基于Hadoop的大规模数据处理系统的组成及原理。

 

Hadoop的组成部分

 

Hadoop是Google的MapReduce一个Java实现。MapReduce是一种简化的分布式编程模式,让程序自动分布到一个由普通机器组成的超大集群上并发执行。

Hadoop主要由HDFS、MapReduce和HBase等组成。具体的组成如下图:

 

 

Hadoop的组成图

1. Hadoop HDFS是Google GFS存储系统的开源实现,主要应用场景是作为并行计算环境(MapReduce)的基础组件,同时也是BigTable(如HBase、HyperTable)的底层分布式文件系统。HDFS采用master/slave架构。一个HDFS集群是有由一个Namenode和一定数目的Datanode组成。Namenode是一个中心服务器,负责管理文件系统的namespace和客户端对文件的访问。Datanode在集群中一般是一个节点一个,负责管理节点上它们附带的存储。在内部,一个文件其实分成一个或多个block,这些block存储在Datanode集合里。Namenode执行文件系统的namespace操作,例如打开、关闭、重命名文件和目录,同时决定block到具体Datanode节点的映射。Datanode在Namenode的指挥下进行block的创建、删除和复制。Namenode和Datanode都是设计成可以跑在普通的廉价的运行Linux的机器上。HDFS采用Java语言开发,因此可以部署在很大范围的机器上。一个典型的部署场景是一台机器跑一个单独的Namenode节点,集群中的其他机器各跑一个Datanode实例。这个架构并不排除一台机器上跑多个Datanode,不过这比较少见。

 

 

HDFS体系结构图

2. Hadoop MapReduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千个商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上TB级别的数据集。

一个MapReduce作业(job)通常会把输入的数据集切分为若干独立的数据块,由 Map任务(task)以完全并行的方式处理它们。框架会对Map的输出先进行排序,然后把结果输入给Reduce任务。通常作业的输入和输出都会被存储在文件系统中。整个框架负责任务的调度和监控,以及重新执行已经失败的任务。

 

Hadoop MapReduce处理流程图

 

3. Hive是基于Hadoop的一个数据仓库工具,处理能力强而且成本低廉。

 

 主要特点:

 

存储方式是将结构化的数据文件映射为一张数据库表。

提供类SQL语言,实现完整的SQL查询功能。

1.可以将SQL语句转换为MapReduce任务运行,十分适合数据仓库的统计分析。

 

不足之处:

 

1.采用行存储的方式(SequenceFile)来存储和读取数据。

2.效率低:当要读取数据表某一列数据时需要先取出所有数据然后再提取出某一列的数据,效率很低。

3.占用较多的磁盘空间。

 

由于以上的不足,查礼博士介绍了一种将分布式数据处理系统中以记录为单位的存储结构变为以列为单位的存储结构,进而减少磁盘访问数量,提高查询处理性能。这样,由于相同属性值具有相同数据类型和相近的数据特性,以属性值为单位进行压缩存储的压缩比更高,能节省更多的存储空间。

 

 行列存储的比较图

HBase是一个分布式的、面向列的开源数据库,它不同于一般的关系数据库,是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。HBase使用和 BigTable非常相同的数据模型。用户存储数据行在一个表里。一个数据行拥有一个可选择的键和任意数量的列,一个或多个列组成一个ColumnFamily,一个Fmaily下的列位于一个HFile中,易于缓存数据。表是疏松的存储的,因此用户可以给行定义各种不同的列。在HBase中数据按主键排序,同时表按主键划分为多个HRegion。

 

HBase数据表结构图

“高端云计算课程”培训将于2010年9月10日正式开始,将会介绍典型云计算平台核心算法,并透过案例讲解企业云计算发展与建设规划。欲知详情,请登录“高端云计算课程”主页。

 DRDA 分布式关系数据库体系结构

DRDA(Distributed Relational Database Architecture )分布式关系数据库体系结构  分布式关系数据库体系结构(DRDA)是一个跨IBM平台访问、遵循SQL标准的数据库信息的IBM标准。它是IBM的信息仓库框架中的重要组成部分,该框架定义了庞大的后台服务器,客户机可通过较小的基于工作组的中介服务器来访问它。DRDA具有下列功能:    定义了客户机和后台数据库之间的接口协议。    提供了IBM的DB2、DBM、SQL/DS和SQL/400数据库系统的互连框架。    支持多供应商提供的数据库系统。    支持分布式数据库上的事务(工作单元)处理。    在DRDA中,客户机叫做应用请求器(ARS),后台服务器叫做应用服务器(AS),协议叫做应用支持协议(ASP),提供AR和AS间的接口。整个过程操作在SNA网上,但也计划支持OSI和TCP/IP。有一个附加的协议叫做数据库支持协议(DSP),它使一个AS能对另一服务器扮演AR的角色。通过这种方法服务器之间能相互通话并传递来自客户AR的请求,如图D-25所示。最初的协议对一个数据库只支持一个结构化查询语言(SQL)的语句,但未来的版本将对一个或多个数据库提供多个语句的支持。    DRDA是IBM环境中建立客户机/服务器计算的基础之一。其它基础是高级的对等联网(APPN)和分布式数据管理(DDM)。通过信息仓库和DRDA,IBM计算机将它的企业中心组成部分的大型计算机,用作各种类型信息(包括多媒体信息)的存储平台。  

 

 

Google文件系统GFS

Google文件系统(Google File System,GFS)是一个大型的分布式文件系统。它为Google云计算提供海量存储,并且与Chubby、MapReduce以及Bigtable等技术结合十分紧密,处于所有核心技术的底层。由于GFS并不是一个开源的系统,我们仅仅能从Google公布的技术文档来获得一点了解,而无法进行深入的研究。

当前主流分布式文件系统有RedHat的GFS[3](Global File System)、IBM的GPFS[4]、Sun的Lustre[5]等。这些系统通常用于高性能计算或大型数据中心,对硬件设施条件要求较高。以Lustre文件系统为例,它只对元数据管理器MDS提供容错解决方案,而对于具体的数据存储节点OST来说,则依赖其自身来解决容错的问题。例如,Lustre推荐OST节点采用RAID技术或SAN存储区域网来容错,但由于Lustre自身不能提供数据存储的容错,一旦OST发生故障就无法恢复,因此对OST的稳定性就提出了相当高的要求,从而大大增加了存储的成本,而且成本会随着规模的扩大线性增长。

正如李开复所说的那样,创新固然重要,但有用的创新更重要。创新的价值,取决于一项创新在新颖、有用和可行性这三个方面的综合表现。Google GFS的新颖之处并不在于它采用了多么令人惊讶的技术,而在于它采用廉价的商用机器构建分布式文件系统,同时将GFS的设计与Google应用的特点紧密结合,并简化其实现,使之可行,最终达到创意新颖、有用、可行的完美组合。GFS使用廉价的商用机器构建分布式文件系统,将容错的任务交由文件系统来完成,利用软件的方法解决系统可靠性问题,这样可以使得存储的成本成倍下降。由于GFS中服务器数目众多,在GFS中服务器死机是经常发生的事情,甚至都不应当将其视为异常现象,那么如何在频繁的故障中确保数据存储的安全、保证提供不间断的数据存储服务是GFS最核心的问题。GFS的精彩在于它采用了多种方法,从多个角度,使用不同的容错措施来确保整个系统的可靠性。

2.1.1 系统架构

GFS的系统架构如图2-1[1]所示。GFS将整个系统的节点分为三类角色:Client(客户端)、Master(主服务器)和Chunk Server(数据块服务器)。Client是GFS提供给应用程序的访问接口,它是一组专用接口,不遵守POSIX规范,以库文件的形式提供。应用程序直接调用这些库函数,并与该库链接在一起。Master是GFS的管理节点,在逻辑上只有一个,它保存系统的元数据,负责整个文件系统的管理,是GFS文件系统中的“大脑”。Chunk Server负责具体的存储工作。数据以文件的形式存储在Chunk Server上,Chunk Server的个数可以有多个,它的数目直接决定了GFS的规模。GFS将文件按照固定大小进行分块,默认是64MB,每一块称为一个Chunk(数据块),每个Chunk都有一个对应的索引号(Index)。

图2-1 GFS体系结构

客户端在访问GFS时,首先访问Master节点,获取将要与之进行交互的Chunk Server信息,然后直接访问这些Chunk Server完成数据存取。GFS的这种设计方法实现了控制流和数据流的分离。Client与Master之间只有控制流,而无数据流,这样就极大地降低了Master的负载,使之不成为系统性能的一个瓶颈。Client与Chunk Server之间直接传输数据流,同时由于文件被分成多个Chunk进行分布式存储,Client可以同时访问多个Chunk Server,从而使得整个系统的I/O高度并行,系统整体性能得到提高。

相对于传统的分布式文件系统,GFS针对Google应用的特点从多个方面进行了简化,从而在一定规模下达到成本、可靠性和性能的最佳平衡。具体来说,它具有以下几个特点。

1.采用中心服务器模式

GFS采用中心服务器模式来管理整个文件系统,可以大大简化设计,从而降低实现难度。Master管理了分布式文件系统中的所有元数据。文件划分为Chunk进行存储,对于Master来说,每个Chunk Server只是一个存储空间。Client发起的所有操作都需要先通过Master才能执行。这样做有许多好处,增加新的Chunk Server是一件十分容易的事情,Chunk Server只需要注册到Master上即可,Chunk Server之间无任何关系。如果采用完全对等的、无中心的模式,那么如何将Chunk Server的更新信息通知到每一个Chunk Server,会是设计的一个难点,而这也将在一定程度上影响系统的扩展性。Master维护了一个统一的命名空间,同时掌握整个系统内Chunk Server的情况,据此可以实现整个系统范围内数据存储的负载均衡。由于只有一个中心服务器,元数据的一致性问题自然解决。当然,中心服务器模式也带来一些固有的缺点,比如极易成为整个系统的瓶颈等。GFS采用多种机制来避免Master成为系统性能和可靠性上的瓶颈,如尽量控制元数据的规模、对Master进行远程备份、控制信息和数据分流等。

2.不缓存数据

缓存(Cache)机制是提升文件系统性能的一个重要手段,通用文件系统为了提高性能,一般需要实现复杂的缓存机制。GFS文件系统根据应用的特点,没有实现缓存,这是从必要性和可行性两方面考虑的。从必要性上讲,客户端大部分是流式顺序读写,并不存在大量的重复读写,缓存这部分数据对系统整体性能的提高作用不大;而对于Chunk Server,由于GFS的数据在Chunk Server上以文件的形式存储,如果对某块数据读取频繁,本地的文件系统自然会将其缓存。从可行性上讲,如何维护缓存与实际数据之间的一致性是一个极其复杂的问题,在GFS中各个Chunk Server的稳定性都无法确保,加之网络等多种不确定因素,一致性问题尤为复杂。此外由于读取的数据量巨大,以当前的内存容量无法完全缓存。对于存储在Master中的元数据,GFS采取了缓存策略,GFS中Client发起的所有操作都需要先经过Master。Master需要对其元数据进行频繁操作,为了提高操作的效率,Master的元数据都是直接保存在内存中进行操作。同时采用相应的压缩机制降低元数据占用空间的大小,提高内存的利用率。

3.在用户态下实现

文件系统作为操作系统的重要组成部分,其实现通常位于操作系统底层。以Linux为例,无论是本地文件系统如Ext3文件系统,还是分布式文件系统如Lustre等,都是在内核态实现的。在内核态实现文件系统,可以更好地和操作系统本身结合,向上提供兼容的POSIX接口。然而,GFS却选择在用户态下实现,主要基于以下考虑。

在用户态下实现,直接利用操作系统提供的POSIX编程接口就可以存取数据,无需了解操作系统的内部实现机制和接口,从而降低了实现的难度,并提高了通用性。

POSIX接口提供的功能更为丰富,在实现过程中可以利用更多的特性,而不像内核编程那样受限。

用户态下有多种调试工具,而在内核态中调试相对比较困难。

用户态下,Master和Chunk Server都以进程的方式运行,单个进程不会影响到整个操作系统,从而可以对其进行充分优化。在内核态下,如果不能很 好地掌握其特性,效率不但不会高,甚至还会影响到整个系统运行的稳定性。

用户态下,GFS和操作系统运行在不同的空间,两者耦合性降低,从而方便GFS自身和内核的单独升级。

4.只提供专用接口

通常的分布式文件系统一般都会提供一组与POSIX规范兼容的接口。其优点是应用程序可以通过操作系统的统一接口来透明地访问文件系统,而不需要重新编译程序。GFS在设计之初,是完全面向Google的应用的,采用了专用的文件系统访问接口。接口以库文件的形式提供,应用程序与库文件一起编译,Google应用程序在代码中通过调用这些库文件的API,完成对GFS文件系统的访问。采用专用接口有以下好处。

降低了实现的难度。通常与POSIX兼容的接口需要在操作系统内核一级实现,而GFS是在应用层实现的。

采用专用接口可以根据应用的特点对应用提供一些特殊支持,如支持多个文件并发追加的接口等。

专用接口直接和Client、Master、Chunk Server交互,减少了操作系统之间上下文的切换,降低了复杂度,提高了效率。

2.1.2 容错机制

1.Master容错

具体来说,Master上保存了GFS文件系统的三种元数据。

命名空间(Name Space),也就是整个文件系统的目录结构。

Chunk与文件名的映射表。

Chunk副本的位置信息,每一个Chunk默认有三个副本。

首先就单个Master来说,对于前两种元数据,GFS通过操作日志来提供容错功能。第三种元数据信息则直接保存在各个Chunk Server上,当Master启动或Chunk Server向Master注册时自动生成。因此当Master发生故障时,在磁盘数据保存完好的情况下,可以迅速恢复以上元数据。为了防止Master彻底死机的情况,GFS还提供了Master远程的实时备份,这样在当前的GFS Master出现故障无法工作的时候,另外一台GFS Master可以迅速接替其工作。

2.Chunk Server容错

GFS采用副本的方式实现Chunk Server的容错。每一个Chunk有多个存储副本(默认为三个),分布存储在不同的Chunk Server上。副本的分布策略需要考虑多种因素,如网络的拓扑、机架的分布、磁盘的利用率等。对于每一个Chunk,必须将所有的副本全部写入成功,才视为成功写入。在其后的过程中,如果相关的副本出现丢失或不可恢复等状况,Master会自动将该副本复制到其他Chunk Server,从而确保副本保持一定的个数。尽管一份数据需要存储三份,好像磁盘空间的利用率不高,但综合比较多种因素,加之磁盘的成本不断下降,采用副本无疑是最简单、最可靠、最有效,而且实现的难度也最小的一种方法。

GFS中的每一个文件被划分成多个Chunk,Chunk的默认大小是64MB,这是因为Google应用中处理的文件都比较大,以64MB为单位进行划分,是一个较为合理的选择。Chunk Server存储的是Chunk的副本,副本以文件的形式进行存储。每一个Chunk以Block为单位进行划分,大小为64KB,每一个Block对应一个32bit的校验和。当读取一个Chunk副本时,Chunk Server会将读取的数据和校验和进行比较,如果不匹配,就会返回错误,从而使Client选择其他Chunk Server上的副本。

2.1.3 系统管理技术

严格意义上来说,GFS是一个分布式文件系统,包含从硬件到软件的整套解决方案。除了上面提到的GFS的一些关键技术外,还有相应的系统管理技术来支持整个GFS的应用,这些技术可能并不一定为GFS所独有。

1.大规模集群安装技术

安装GFS的集群中通常有非常多的节点,文献[1]中最大的集群超过1000个节点,而现在的Google数据中心动辄有万台以上的机器在运行。因此迅速地安装、部署一个GFS的系统,以及迅速地进行节点的系统升级等,都需要相应的技术支撑。

2.故障检测技术

GFS是构建在不可靠的廉价计算机之上的文件系统,由于节点数目众多,故障发生十分频繁,如何在最短的时间内发现并确定发生故障的Chunk Server,需要相关的集群监控技术。

3.节点动态加入技术

当有新的Chunk Server加入时,如果需要事先安装好系统,那么系统扩展将是一件十分烦琐的事情。如果能够做到只需将裸机加入,就会自动获取系统并安装运行,那么将会大大减少GFS维护的工作量。

4.节能技术

有关数据表明,服务器的耗电成本大于当初的购买成本,因此Google采用了多种机制来降低服务器的能耗,例如对服务器主板进行修改,采用蓄电池代替昂贵的UPS(不间断电源系统),提高能量的利用率。Rich Miller 在一篇关于数据中心的博客文章中表示,这个设计让 Google 的 UPS 利用率达到99.9%,而一般数据中心只能达到92%~95%。

分布式系统存储设计

曾几何时,分布式计算成为一种潮流,伴之而来的分散存储所带来的高额管理费用已成为企业的一大笔开支,且给企业的业务发展带来许多负面影响。存储整合解决方案正是针对这类情况所设计。 现状及问题 随着计算机应用的不断深入,目前企业的业务系统采用计算机来实现和存储关键数据,已是非常普遍的现象。在过去的几年,有这么一种观点:企业采用计算机系统和存储系统最好采用“分布式计算”的方式。这种“分布式计算”的核心是:企业中每个部门选择各自不同的电脑系统。因为每个部门各有各的业务,对不同品牌和平台也各有偏好,选择各自熟悉的平台,以部门为单位分开,可以方便管理,同时节约成本。随着这几年的实践,人们发现这一想法走向了它初衷的反面,具体体现在: 1. 数据格式的不统一所导致的管理困难,不利于业务的发展。多年以来,各地方各自为政,按照自己的喜好采购硬件,开发软件系统,导致不同的系统平台,数据格式也不完全统一,数据之间的迁移/转换更加复杂,需要额外的硬件和软件支持;而且,最为关键的是总公司没有一本完整的账目,不能做出及时的决策,对企业的发展和竞争极为不利; 2. 分布式管理所带的巨额管理费用已经得不偿失。以前,企业往往会陷入一个误区,认为分布式管理会节省费用,但一旦购买了一定量的存储容量后,管理费用(维护费用,升级费用,人工费用等)成为最大的支出项目,而且这笔支出将贯穿整个产品的生命周期,因此管理费用是整套产品的最大投资,而且这个管理费用还在不断上升。右图比较了三种不同存储分布的情况下,花相同的管理费用实际可管理到的存储容量。第一种情况为一个跨地域的企业将存储分散在不同的地域分开管理;第二种情况为一个跨地域的企业将存储集中在一个地方,但依然分为不同系统管理。第三种情况为完全存储整合方案,即同一系统同一地域的管理。如图所示,第三种方式可极大的降低成本同时方便管理。   图:同样的开支在不同环境下所能管理的容量 因此,银行,电信等均在着手对存储数据进行整合。   今天来说,集中化的存储管理思想是一种非常有效的经济的存储管理解决方案。因为对于磁盘阵列来说,只有一套管理系统,这样就可以极为方便地进行磁盘监控,性能调试。增加或者重新配置磁盘也变得非常简单。最大化的合成集中设备,也使得存储系统的宕机风险降至最低。同时,一套完善的备份方案就可以有效地进行数据备份及恢复。 惠普提供两种存储整合解决方案。 1. 单一存储设备整合:   将数据库和OA的数据集中存放在同一存储设备上。该存储设备支持开放标准,可连结不同平台的服务器(hp,sun,IBM、NTServer等),如hp的SureStore系列存储设备中的XP512、XP48等。下图为整合后的逻辑示意图: 2. 存储区域网(SAN)整合 存储整合的终极目标是构成存储区域网,即由存储区域网完成数据的读、写、备份和容灾,无需占用企业内部的通信网络(LAN-Free)。前端的用户无需考虑数据的存放位置,数据保护机制,备份策略等,仅仅象用自来水那样拧开水龙头。具体请参照存储网络方案介绍。   下图为整合后的存储区域网的示意图: 对比两种存储解决方案,两者均采用惠普的同一存储设备,因而能够 1. 有效利用总存储空间,节约投资;假设某台主机设备的存储空间不足,均可动态地进行调整,将其他主机暂时未占用的空间进行分配,从而避免重复投资。 2. 能够集中备份和维护,轻松管理;设备集中在某一中心,一方面,只需少量的专业管理人员,维护起来也更加容易,另一方面,总公司也便于提起数据来支持决策支持系统。 3. 只需与一家厂商沟通,便于得到最好的服务。和以前方式不同,并非每家主机系统配置自己的存储设备,因而,一旦出现问题,需要和多家厂商进行沟通,甚至还会出现踢皮球现象,现在存储设备能够支持多平台,不会存在此类现象。 但前一种解决方案,需要通过局域网实现某些存储和备份功能,存在网络瓶颈,而采用SAN整合方式,则解决了网络瓶颈问题,最大限度地提高整套系统的性能。 方案的优点 存储整合一直是惠普公司关注的焦点,同时惠普公司在用户存储系统整合的方案设计和实施方面积累了丰富的经验和大量的成功案例。通过建立惠普存储整合计算环境后: 1. 可以极大地保护用户的投资,降低用户管理费用,从而 确保整体拥有成本最低。 2. 降低管理难度,维护数据管理的统一性。 3. 提高了电子化数据管理的可靠性。数据的集中化管理, 能够确保数据的一致性和完整性,保证电子化数据的可 靠性。 4. 开放的标准,能够支持多平台的整合,包括:hp UX, IBM AIX, Sun Solaris和Microsoft,Windows NT, W2K.   方案配置 单一存储设备整合配置: 服务器: Option1: hp 9000 Unix服务器; hp NetServer PC服务器; Option2: IBM AIX或COMPAQ ALPHA, SUN Solaris其他NT服务器 存储设备: hp SureStore XP48或XP512磁盘阵列 hp SureStore Tape Library 6/140,10/180,20/700 软件: hp SureSoft软件 Option1: hp OmnibackII备份软件及选件 Option2: Veritas NetBackup(hp UX, Solaris, NT) 备份软件及选件 Option3: Veritas Backup Exec(NT)备份软件及选件 Option4:CA ARCserve备份软件及选件 Option5: Legato Networker备份软件及选件 hp SAN存储设备整合配置: 服务器: Option1: hp 9000 Unix服务器; hp NetServer PC服务器; Option2: IBM AIX 或COMPAQALPHA,   SUN Solaris其他NT服务器 存储设备: hp SureStore XP48或XP512磁盘阵列 hp SureStore Tape Library 6/140,10/180,20/700 其他硬件设备: hp SureStore SCSI Bridge FC4/2 Brocade Silkworm Switch 2400/2800 Emulex LP8000 主机总线适配卡(NT/WIN2K/AIX) Qlogic QLA2200F主机总线适配卡(NT/WIN2K) JNI FCE6410-N主机总线适配卡(NT/WIN2K) JNI FC641063主机总线适配卡(Solaris, Sbus总线) JNI FCI-1063 主机总线适配卡(Solaris,PCI总线) 光纤通道或广域网接口 软件: hp SureSoft软件 Option1: hp OmnibackII备份软件及选件 Option2: Veritas NetBackup(hp UX, Solaris, NT) 备份软件及选件 Option3: Veritas Backup Exec(NT)备份软件及选件 Option4: CA ARCserve备份软件及选件 Option5: Legato Networker备份软件及选件 适用范围 惠普的存储整合方案适用于企业计算环境中有不同的存储平台,或存储设备分散在不同场所,希望通过存储整合降低成本,同时提高可管理性的场合。

 

可维护性分布式存储系统和分离的分布式系统

1.分布式系统的应该有两种基本的层次的架构。

       1.1.普通的分布式系统架构,是典型的三层的架构,如下图的分离的分布式系统的一个子系统。

       1.2.多个分布式系统构成的分布式系统的超级,可以构建云服务的分布式系统。

 

2.普通的分布式系统的构成

2.1简单分布式的组合构成的服务系统

  一般的分布式系统都具有三层架构层次,hand,master,svr。master保存路由表,hand为接入,svr为真正的逻辑服务器。可以对master的路由表操作实现分布。master动态探测svr的存活,进行路由表的更新。

  如果单纯的逻辑服务器(不带cache),这里的路由表的更新较为方便和简洁。如果是带有cache 的逻辑服务器则需要根据是脏cache还是干净cache,并迁移cache 的数据。由于在迁移过程中一般会对服务有影响,如果是脏cache,则需要等到迁移完成才能进行服务,这里就有个格子锁定的状态。因此对于具有脏cache 的服务分布式系统,复杂程度大了很多。并且在迁移的时候会影响到服务。

 

 

 

 

 

                                             图一  各个分布式的简单组合构成的服务系统典型架构

 

       上图中有些系统没有hand模块是因为其master可能只需要管理其路由表。而路由表的拉取直接放在上一层的逻辑服务器。其接入机是镜像的接入。这种逻辑服务系统一般只能较小规模的业务接入和应用。原有有以下几点:

       2.1.1.各个自己系统的具有自己的简单容灾机制,但是没有总体的容灾机制,

       2.1.2.所有的接入是镜像的,则其配置都是一样的,如果这个系统承载多个服务,则无法轻松对其近区别服务,迁移和管理。即一个系统一旦搭建也运行,则很难对业务应用的服务进行控制,控制的粒度则一个系统级别。

       2.1.3.其承载的业务愈多,则风险系数陡增。其接入服务器的bug会 导致所有服务的中断,其后端的逻辑服务器的bug会导致其一个系统的瘫痪。其业务的灰度升级无法做到真正意义上的灰度。因为其子系统没有业务管理的功能。无论灰度那一台机器,其影响都是系统的所有业务,一旦出现bug,将会对所有的业务产生影响。无法做到业务和机器的灰度,只能做到机器这个低级别的灰度。

 

       因此这种分布式的简单组合无法承载较大业务的运行,只有将一定数量的业务放在一个系统,这样风险或许可承受,但是如果系统有所发展,接入的业务和应用越来越多,将会维护这样若干的系统。造成运维上的麻烦和低效率。

 

3.可维护的分布式系统

  3.1 下面介绍可维护的分布式系统的构成和基本设计思想。目标就是要构建支持大规模业务应用的存储分布式存储系统。

    既然是存储系统,那么就会容纳许多业务,这个系统才有意义。当前的能够容纳很多业务的成熟概念就是云的概念,没错,我么就是要构建这样一个具有云系统概念的分布式存储系统。

    其基本目标就是要能够轻松的做到对不同业务的管理和维护,调度。在大规模的业务的场景下,能够很好的支撑和运营。

   下面是其基本的架构思想。

 

 3.2基本设计思想:

       3.2.1 整个系统由统一的接入,统一的控制中心组成,后端的逻辑分布式子系统组成

       3.2.2 整个系统的master都具有容灾,路由和按照一个中心master的指令来进行操作的功能,即中心master具有管理的功能,能够对业务进行控制和管理,然后根据策略中心生成的策略对整个系统进行均衡,迁移和管理操作。

       3.2.3 支持大规模的业务接入,提高系统的安全性。如果某一个业务有故障,中心master可以根据一定的策略将其布置在单独的机器行,并且将其他业务部署在其他机器上,实现业务的快速隔离。

       3.2.4 其对业务级别和机器级别,模块级别的灰度将表现非常优秀。中心master可以部署某个业务的某些访问在灰度的机器上。灰度的控制非常灵活和到位。

 

4.总结

 

      具有可维护的分布式系统需要一个统一的控制中心。即cmaster(中心控制器)。可以对业务进行很好的调度和控制,所有的master

都应该具有这样的功能,具有调度和控制的功能。这样的系统才具有云服务系统的基础

 

集中式,分布式,协作式数据处理的区别

1)集中式数据处理 集中式计算机网络由一个大型的中央系统,其终端是客户机,数据全部存储在中央系统,由数据库管理系统进行管理,所有的处理都由该大型系统完成,终端只是用来输入和输出。终端自己不作任何处理,所有任务都在主机上进行处理。     集中式数据存储的主要特点是能把所有数据保存在一个地方,各地办公室的远程终端通过电缆同中央计算机(主机)相联,保证了每个终端使用的都是同一信息。备份数据容易,因为他们都存储在服务器上,而服务器是唯一需要备份的系统。这还意味这服务器是唯一需要安全保护的系统,终端没有任何数据。银行的自动提款机(ATM)采用的就是集中式计算机网络。另外所有的事务都在主机上进行处理,终端也不需要软驱,所以网络感染病毒的可能性很低。这种类型的网络总费用比较低,因为主机拥有大量存储空间、功能强大的系统,而使终端可以使用功能简单而便宜的微机和其他终端设备。 这类网络不利的一面是来自所有终端的计算都由主机完成,这类网络处理速度可能有些慢。另外,如果用户有各种不同的需要,在集中式计算机网络上满足这些需要可能是十分困难的,因为每个用户的应用程序和资源都必须单独设置,而让这些应用程序和资源都在同一台集中式计算机上操作,使得系统效率不高。还有,因为所有用户都必须连接到一台中央计算机,集中连接可能成为集中式网络的一个大问题。由于这些限制,如今的大多数网络都采用了分布式和协作式网络计算模型。 2)分布式数据处理 由于个人计算机的性能得到极大的提高及其使用的普及,使处理能力分布到网络上的所有计算机成为可能。分布式计算是和集中式计算相对立的概念,分布式计算的数据可以分布在很大区域。 分布式网络中,数据的存储和处理都是在本地工作站上进行的。数据输出可以打印,也可保存在软盘上。通过网络主要是得到更快、更便捷的数据访问。因为每台计算机都能够存储和处理数据,所以不要求服务器功能十分强大,其价格也就不必过于昂贵。这种类型的网络可以适应用户的各种需要,同时允许他们共享网络的数据、资源和服务。在分布式网络中使用的计算机既能够作为独立的系统使用,也可以把它们连接在一起得到更强的网络功能。 分布式计算的优点是可以快速访问、多用户使用。每台计算机可以访问系统内其他计算机的信息文件;系统设计上具有更大的灵活性,既可为独立的计算机的地区用户的特殊需求服务,也可为联网的企业需求服务,实现系统内不同计算机之间的通信;每台计算机都可以拥有和保持所需要的最大数据和文件;减少了数据传输的成本和风险。为分散地区和中心办公室双方提供更迅速的信息通信和处理方式,为每个分散的数据库提供作用域,数据存储于许多存储单元中,但任何用户都可以进行全局访问,使故障的不利影响最小化,以较低的成本来满足企业的特定要求。 分布式计算的缺点是:对病毒比较敏感,任何用户都可能引入被病毒感染的文件,并将病毒扩散到整个网络。备份困难,如果用户将数据存储在各自的系统上,而不是将他们存储在中央系统中,难于制定一项有效的备份计划。这种情况还可能导致用户使用同一文件的不同版本。为了运行程序要求性能更好的PC机;要求使用适当的程序;不同计算机的文件数据需要复制;对某些PC机要求有足够的存储容量,形成不必要的存储成本;管理和维护比较复杂;设备必须要互相兼容。 3)协作式数据处理 协作式数据处理系统内的计算机能够联合处理数据,处理既可集中实施,也可分区实施。协作式计算允许各个客户计算机合作处理一项共同的任务,采用这种方法,任务完成的速度要快于仅在一个客户计算机运行。协作式计算允许计算机在整个网络内共享处理能力,可以使用其它计算机上的处理能力完成任务。除了具有在多个计算机系统上处理任务的能力,该类型的网络在共享资源方面类似于分布式计算。 协作式计算和分布式计算具有相似的优缺点。例如协作式网络上可以容纳各种不同的客户,协作式计算的优点是处理能力强,允许多用户使用。缺点是病毒可迅速扩散到整个网络。因为数据能够在整个网络内存储,形成多个副本,文件同步困难。并且也使得备份所有的重要数据比较困难。

 

 

Google Megastore分布式存储技术全揭秘

 

Megastore是谷歌一个内部的存储系统,它的底层数据存储依赖Bigtable,也就是基于NoSql实现的,但是和传统的NoSql不同的 是,它实现了类似RDBMS的数据模型(便捷性),同时提供数据的强一致性解决方案(同一个datacenter,基于MVCC的事务实现),并且将数据 进行细颗粒度的分区(这里的分区是指在同一个datacenter,所有datacenter都有相同的分区数据),然后将数据更新在机房间进行同步复制 (这个保证所有datacenter中的数据一致)。

Megastore的数据复制是通过paxos进行同步复制的,也就是如果更新一个数据,所有机房都会进行同步更新,因为使用paxos进行复制, 所以不同机房针对同一条数据的更新复制到所有机房的更新顺序都是一致的,同步复制保证数据的实时可见性,采用paxos算法则保证了所有机房更新的一致 性,所以个人认为megastore的更新可能会比较慢,而所有读都是实时读(对于不同机房是一致的),因为部署有多个机房,并且数据总是最新。

为了达到高可用性,megastore实现了一个同步的,容错的,适合长距离连接的日志同步器

为了达到高可扩展性,megastore将数据分区成一个个小的数据库,每一个数据库都有它们自己的日志,这些日志存储在NoSql中

Megastore将数据分区为一个Entity Groups的集合,这里的Entity Groups相当于一个按id切分的分库,这个Entity Groups里面有多个Entity Group(相当于分库里面的表),而一个Entity Group有多个Entity(相当于表中的记录)

在同一个Entity Group中(相当于单库)的多个Entity的更新事务采用single-phase ACID事务,而跨Entity Group(相当于跨库)的Entity更新事务采用two-phase ACID事务(2段提交),但更多使用Megastore提供的高效异步消息实现。需要说明的一点是,这些事务都是在同一个机房的,机房之间的数据交互都 是通过数据复制来实现的。

传统关系型数据库使用join来满足用户的需求,对于Megastore来说,这种模型(也就是完全依赖join的模型)是不合适的。原因包括

1.高负载交互性型应用能够从可预期的性能提升得到的好处多于使用一种代价高昂的查询语言所带来的好处。

2.Megastore目标应用是读远远多于写的,所以更好的方案是将读操作所需要做的工作转移到写操作上面(比如通过具体值代替外键以消除join)

3.因为megastore底层存储是采用BigTable,而类似BigTable的key-value存储对于存取级联数据是直接的

所以基于以上几个原因,Megastore设计了一种数据模型和模式语言来提供基于物理地点的细颗粒度控制,级联布局,以及申明式的不正规数据存储来帮助消除大部分joins。查询时只要指定特定表和索引即可。

当然可能有时候不得不使用到join,Megastore提供了一种合并连接算法实现,具体算法这里我还是没弄清楚,原文是[the user providesmultiple queries that return primary keys for the same table in the same order;we then return the intersection of keys for all the provided queries.]

使用Megastore的应用通过并行查询实现了outer joins。通常先进行一个初始的查询,然后利用这个查询结果进行并行索引查询,这个过程我理解的是,初始查询查出一条数据,就马上根据这个结果进行并行 查询,这个时候初始查询继续取出下一条数据,再根据这个结果并行查询(可能前面那个外键查询还在继续,使用不同的线程)。这种方法在初始查询数据量较小并 且外键查询使用并行方式的情况下,是一种有效的并且具有sql风格的joins。

Megastore的数据结构介于传统的RDBMS和NoSql之间的,前者主要体现在他的schema表示上,而后者体现在具体的数据存储上 (BigTable)。和RDBMS一样,Megastore的数据模型是定义schema中并且是强类型的。每一个schema有一个表集合,每个表包 含一个实体集合(相当于record),每个实体有一系列的属性(相当于列属性),属性是命名的,并且指定类型,这些类型包括字符串,各种数字类型,或者google的protocol buffer。这些属性可以被设置成必需的,可选的,或者可重复的(一个属性上可以具有多个值)。一个或者多个属性可以组成一个主键。

在上图中,User和Photo共享了一个公共属性user_id,IN TABLE User这个标记直接将Photo和User这两张表组织到了同一个BigTable中,并且键的顺序(PRIMARY KEY(user_id,photo_id)?是这个还是schema中定义的顺序?)保证Photo的实体存储在对应的User实体邻接位置上。这个机 制可以递归的应用,加速任意深度的join查询速度。这样,用户能够通过操作键的顺序强行改变数据级联的布局。其他标签请参考原文。

Megastore支持事务和并发控制。一个事务写操作会首先写入对应Entity Group的日志中,然后才会更新具体数据。BigTable具有一项在相同row/column中存储多个版本带有不同时间戳的数据。正是因为有这个特 性,Megastore实现了多版本并发控制(MVCC,这个包括oracle,innodb都是使用这种方式实现ACID,当然具体方式会有所不同): 当一个事务的多个更新实施时,写入的值会带有这个事务的时间戳。读操作会使用最后一个完全生效事务的时间戳以避免看到不完整的数据.读写操作不相互阻塞, 并且读操作在写事务进行中会被隔离(?)。

Megastore 提供了current,snapshot,和inconsistent读,current和snapshot级别通常是读取单个entity group。当开始一个current读操作时,事务系统会首先确认所有之前提交的写已经生效了;然后系统从最后一个成功提交的事务时间戳位置读取数据。 对于snapshot读取,系统拿到己经知道的完整提交的事务时间戳并且从那个位置直接读取数据,和current读取不同的是,这个时候可能提交的事务 更新数据还没有完全生效(提交和生效是不同的)。Megastore提供的第三种读就是inconsistent读,这种读无视日志状态并且直接读取最后 一个值。这种方式的读对于那些对减少延迟有强烈需求,并且能够容忍数据过期或者不完整的读操作是非常有用的。

一个写事务通常开始于一个current读操作以便确定下一个可用的日志位置。提交操作将数据变更聚集到日志,并且分配一个比之前任何一个都高的时 间戳,并且使用Paxos将这个log entry加入到日志中。这个协议使用了乐观并发:即使有可能有多个写操作同时试图写同一个日志位置,但只会有1个成功。所有失败的写都会观察到成功的写 操作,然后中止,并且重试它们的操作。咨询式的锁定能够减少争用所带来的影响。通过特定的前端服务器分批写入似乎能够完全避免竞争(这几句有些不能理解) [ Advisory lockingis available to reduce the effects of contention. Batching writes throughsession affinity to a particular front-end server can avoid contentionaltogether.]。

完整事务生命周期包括以下步骤:

1.读:获取时间戳和最后一个提交事务的日志位置

2.应用逻辑:从BigTable读取并且聚集写操作到一个日志Entry

3.提交:使用Paxos将日志Entry加到日志中

4.生效:将数据更新到BigTable的实体和索引中

5.清理:删除不再需要的数据

写操作能够在提交之后的任何点返回,但是最好还是等到最近的副本(replica)生效(再返回)。

Megastore提供的消息队列提供了在不同Entity Group之间的事务消息。它们能被用作跨Entity Group的操作,在一个事务中分批执行多个更新,或者延缓工作(?)。一个在单个Entity Group上的事务能够原子性地发送或者收到多个信息除了更新它自己的实体。每个消息都有一个发送和接收的Entity Group;如果这两个Entity Group是不同的,那么传输将会是异步的。

消息队列提供了一种将会影响到多个Entity Group的操作的途径,举个例子,日历应用中,每一个日历有一个独立的Entity Group,并且我们现在需要发送一个邀请到多个其他人的日历中,一个事务能够原子地发送邀请消息到多个独立日历中。每个日历收到消息都会把邀请加入到它 自己的事务中,并且这个事务会更新被邀请人状态然后删除这个消息。Megastore大规模使用了这种模式:声明一个队列后会自动在每一个Entity Group上创建一个收件箱。

Megastore支持使用二段提交进行跨Entity Group的原子更新操作。因为这些事务有比较高的延迟并且增加了竞争的风险,一般不鼓励使用。

接下来内容具体来介绍下Megastore最核心的同步复制模式:一个低延迟的Paxos实现。Megastore的复制系统向外提供了一个单一 的,一致的数据视图,读和写能够从任何副本(repli ca)开始,并且无论从哪个副本的客户端开始,都能保证ACID语义。每个Entity Group复制结束标志是将这个Entity Group事务日志同步地复制到一组副本中。写操作通常需要一个数据中心内部的网络交互,并且会跑检查健康状况的读操作。current级别的读操作会有 以下保证:

1.一个读总是能够看到最后一个被确认的写。(可见性)

2.在一个写被确认后,所有将来的读都能够观察到这个写的结果。(持久性,一个写可能在确认之前就被观察到)

数据库典型使用Paxos一般是用来做事务日志的复制,日志中每个位置都由一个Paxos实例来负责。新的值将会被写入到之前最后一个被选中的位置之后。

Megastore在事先Paxos过程中,首先设定了一个需求,就是current reads可能在任何副本中进行,并且不需要任何副本之间的RPC交互。因为写操作一般会在所有副本上成功,所以允许在任何地方进行本地读取是现实的。这 些本地读取能够很好地被利用,所有区域的低延迟,细颗粒度的读取failover,还有简单的编程体验。

Megastore设计实现了一个叫做Coordinator(协调者)的服务,这个服务分布在每个副本的数据中心里面。一个 Coordinator服务器跟踪一个Entity Groups集合,这个集合中的Entity Groups需要具备的条件就是它们的副本已经观察到了所有的Paxos写。在这个集合中的Entity Groups,它们的副本能够进行本地读取(local read)。

写操作算法有责任保持Coordinator状态是保守的,如果一个写在一个副本上失败了,那么这次操作就不能认为是提交的,直到这个entity group的key从这个副本的coordinator中去除。(这里不明白)

为了达到快速的单次交互的写操作,Megastore采用了一种Master-Slave方式的优化,如果一次写成功了,那么会顺带下一次写的保证 (也就是下一次写就不需要prepare去申请一个log position),下一次写的时候,跳过prepare过程,直接进入accept阶段。Megastore没有使用专用的Masters,但是使用 Leaders。

Megastore为每一个日志位置运行一个Paxos算法实例。[ The leader for each log position is a

distinguished replicachosen alongside the preceding log position's consensus value.] Leader仲裁在0号提议中使用哪一个值。第一个写入者向Leader提交一个值会赢得一个向所有副本请求接收这个值做为0号提议最终值的机会。所有其 他写入者必需退回到Paxos的第二阶段。

因为一个写入在提交值到其他副本之前必需和Leader交互,所以必需尽量减少写入者和Leader之间的延迟。Megastore设计了它们自己 的选取下一个写入Leader的规则,以同一地区多数应用提交的写操作来决定。这个产生了一个简单但是有效的原则:使用最近的副本。(这里我理解的是哪个 位置提交的写多,那么使用离这个位置最近的副本做为Leader)

Megastore的副本中除了有日志有Entity数据和索引数据的副本外,还有两种角色,其中一种叫做观察者(Witnesses),它们只写 日志,并且不会让日志生效,也没有数据,但是当副本不足以组成一个quorum的时候,它们就可以加入进来。另外一种叫只读副本(Read-Only), 它刚刚和观察者相反,它们只有数据的镜像,在这些副本上只能读取到最近过去某一个时间点的一致性数据。如果读操作能够容忍这些过期数据,只读副本能够在广 阔的地理空间上进行数据传输并且不会加剧写的延迟。

上图显示了Megastore的关键组件,包括两个完整的副本和一个观察者。应用连接到客户端库,这个库实现了Paxos和其他一些算法:选择一个副本进行读,延迟副本的追赶,等等。

Each applicationserver has a designated local replica. The client library makes Paxosoperations on that replica durable by submitting transactions directly to thelocal Bigtable.To minimize wide-area roundtrips, the library submits remotePaxos operations to stateless intermediary replication servers communicatingwith their local Bigtables.

客户端,网络,或者BigTable失败可能让一个写操作停止在一个中间状态。复制的服务器会定期扫描未完成的写入并且通过Paxos提议没有操作的值来让写入完成。

接下来介绍下Megastore的数据结构和算法,每一个副本存有更新和日志Entries的元数据。为了保证一个副本能够参与到一个写入的投票中 即使是它正从一个之前的宕机中恢复数据,Megastore允许这个副本接收不符合顺序的提议。Megastore将日志以独立的Cells存储在 BigTable中。

当日志的前缀不完整时(这个前缀可能就是一个日志是否真正写入的标记,分为2段,第一段是在写入日志之前先写入的几个字节,然后写入日志,第二段是 在写入日志之后写入的几个字节,只有这个日志前缀是完整的,这个日志才是有效的),日志将会留下holes。下图表示了一个单独Megastore Entity Group的日志副本典型场景。0-99的日志位置已经被清除了,100的日志位置是部分被清除,因为每个副本都会被通知到其他副本已经不需要这个日志 了。101日志位置被所有的副本接受了(accepted),102日志位置被Y所获得,103日志位置被A和C副本接受,B副本留下了一个 hole,104日志位置因为副本A和B的不一致,复本C的没有响应而没有一致结果。

在一个current读的准备阶段(写之前也一样),必需有一个副本要是最新的:所有之前更新必需提交到那个副本的日志并且在该副本上生效。我们叫这个过程为catchup。

省略一些截止超时的管理,一个current读算法步骤如下:

1.本地查询:查询本地副本的Coordinator,判定当前副本的Entity Group是最新的

2.查找位置:确定最高的可能已提交的日志位置,然后选择一个己经将这个日志位置生效的副本

a.(Local read) 如果步骤1发现本地副本是最新的,那么从本地副本中读取最高的被接受(accepted)的日志位置和时间戳。

b.(Majority read)如果本地副本不是最新的(或者步骤1或步骤2a超时),那么从一个多数派副本中发现最大的日志位置,然后选取一个读取。我们选取一个最可靠的或者最新的副本,不一定总是是本地副本

3.追赶:当一个副本选中之后,按照下面的步骤追赶到已知的日志位置:

a.对于被选中的不知道共识值的副本中的每一个日志位置,从另外一个副本中读取值。对于任何一个没有已知已提交的值的日志位置,发起一个没有操作的写操作。Paxos将会驱动多数副本在一个值上打成共识-----可能是none-op的写操作或者是之前提议的写操作

b.顺序地将所有没有生效的日志位置生效成共识的值,并将副本的状态变为到分布式共识状态(应该是Coordinator的状态更新)

如果失败,在另外一个副本上重试。

4.验证:如果本地副本被选中并且之前没有最新,发送一个验证消息到coordinator断定(entitygroup,replica)能够反馈(reflects)所有提交的写操作。不要等待回应----如果请求失败,下一个读操作会重试。

5.查询数据:从选中的副本中使用日志位置所有的时间戳读取数据。如果选中的副本不可用,选取另外一个副本重新开始执行追赶,然后从它那里读取。一个大的读取结果有可能从多个副本中透明地读取并且组装返回

注意在实际使用中 1和2a通常是并行执行的。

在完整的读操作算法执行后,Megastore发现了下一个没有使用的日志位置,最后一个写 操作的时间戳,还有下一个leader副本。在提交时刻,所有更新的状态都变为打包的(packaged)和提议(proposed),并且包含一个时间 戳和下一个leader 候选人,做为下一个日志位置的共识值。如果这个值赢得了分布式共识,那么这个值将会在所有完整的副本中生效。否则整个事务将会终止并且必需重新从读阶段开 始。

就像上面所描述的,Coordinators跟踪Entity Groups在它们的副本中是否最新。如果一个写操作没有被一个副本接受,我们必需将这个Entity Group的键从这个副本的Coordinator中移除。这个步骤叫做invalidation(失效)。在一个写操作被认为提交的并且准备生效,所有 副本必需已经接受或者让这个Entity Group在它们coordinator上失效。

写算法的步骤如下:

1.接受Leader:请求Leader接受值做为0号提议的值。如果成功。跳到第三步

2.准备:在所有副本上执行Paxos Prepare阶段,使用一个关于当前log位置更高的提议号。将值替换成拥有最高提议号的那个值。[Replace the valuebeing written withthe highest-numbered proposal discovered, if any]

3.接受:请求余下的副本接受这个值。如果多数副本失败,转到第二步。

4.失效:将没有接受值的副本coordinator失效掉。错误处理将在接下来描述

5.生效:将更新在尽可能多的副本上生效。如果选择的值不同于原始提议的,返回冲突错误[?]

Coordinator进程在每一个数据中心运行并且只保持其本地副本的状态。在上述的写入算法中,每一个完整的副本必需接受或者让其 coordinator失效,所以这个可能会出现任何单个副本失效就会引起不可用。在实际使用中这个不是一个寻常的问题。Coordinator是一个简 单的进程,没有其他额外的依赖并且没有持久存储,所以它表现得比一个BigTable服务器更高的稳定性。然而,网络和主机失败仍然能够让 coordinator不可用。

Megastore使用了Chubby锁服务:Coordinators在启动的时候从远程数据中心获取指定的Chubby locks。为了处理请求,一个Coordinator必需持有其多数locks。一旦因为宕机或者网络问题导致它丢失了大部分锁,它就会恢复到一个默认 保守状态----认为所有在它所能看见的Entity Groups都是失效的。随后(该Coordinator对应的)副本中的读操作必需从多数其他副本中得到日志位置直到Coordinator重新获取到 锁并且Coordinator的Entries重新验证的。

写入者通过测试一个Coordinator是否丢失了它的锁从而让其在Coordinator不可用过程中得到保护:在这个场景中,一个写入者知道在恢复之前Coordinator会认为自己是失效的。

在一个数据中心活着的Coordinator突然不可用时,这个算法需要面对一个短暂(几十秒)的写停顿风险---所有的写入者必需等待 Coordinator的Chubby locks过期(相当于等待一个master failover后重新启动),不同于master failover,写入和读取都能够在coordinator状态重建前继续平滑进行。

除了可用性问题,对于Coordinator的读写协议必需满足一系列的竞争条件。失效的信息总是安全的,但是生效的信息必需小心处理。在 coordinator中较早的写操作生效和较晚的写操作失效之间的竞争通过带有日志位置而被保护起来。标有较高位置的失效操作总是胜过标有较低位置的生 效操作。一个在位置n的失效操作和一个在位置m=2 && id

关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.1697s