NoSQL初探

jopen 10年前

一般数据库的使用方式

  1. 集成数据库:数据共享与数据通信

  2. 应用程序数据库:数据只由某个应用程序负责,交互采用应用程序接口(Web服务形式,被很多叫为SOA)

 

NoSQL的来源与规范

NoSQL这个名字本身来自于一个聚会,该聚会为了推ter的话题便于搜索,起了这个名字。

NoSQL目前没有官方的规范,几个典型的特征是:

  1. 非关系型数据库

  2. 一般是面向集群的

  3. 一般是开源的

  4. 数据存储无需声明和保持一致的格式(无模式)

 

NoSQL数据库分类

主要有四类:

  1. 列族(HBase,Cassandra,Amazon SimpleDB,Hypertable)

  2. 文档(MongoDB,CouchDB,Terrastore、OrientDB、RavenDB)

  3. 键值(Riak,Redis,LevelDB, Memcached DB, HamsterDB)

  4. 图(HyperGraphDB,Neo4J,Infinite Graph,OrientDB,FlockDB)

详细可以参考

http://nosql-database.org/

 

键值数据库

类似一张HASH表。有两列,存放键、值。

只对单个键的操作具备一致性

查询方式以关键字查询为主,所以可能大部分精力花在设计键名上。

适合场景:存放会话信息,以session id为键;用户配置信息,user id;购物车;

不适合场景:不同数据集间欲建立关系;含有多项操作,比如需要联动回滚;查询数据为主;操作多个关键字

 

文档数据库

文档的格式可以是XML, JSON, BSON(BinaryJSON,MongoDB所用的二进制数据文件)。文档数据库存放的“文档”可以类比键值数据库中的“值”

MongoDB中以replica set的方式解决一致性问题,写入操作必须等待所写数据复制到全部或是给定数量的从节点之后,才能返回。

文档数据库可以查询文档中的数据,而不用像键值数据库,必须根据关键字获取整个文档,然后再检索其内容。各文档数据库提供了不同的查询功能。CouchDB可通过视图查询,物化视图或动态视图。 MongoDB支持一种JSON格式的查询语言,包括MYMquery实现where语句,MYMorderby实现排序,MYMexplain列出执行计划等。如SQL中select * from A 等价的Mongo Shell为db.A.find()。

适用场景:事件记录;内容管理系统或博客系统;网站分析或实时分析,如页面浏览量;电子商务应用,存贮订单等

不适合场景:包含多项操作的复杂事务;查询持续变化的聚合节奏,即类似SQL语句外连接的表总变动。

列族数据库

列族数据库将数据存贮在列族中,列族里的行把许多列数据与本行的行健(row key)关联起来。可以存储关键字及其映射值,病可以把值分成多个列族,让每个列族代表一张数据映射表。

列族与关系数据库的行容器对照,都有关键字表示行,每行由多列组成,但是区别在于列族数据库的每行不一定有相同的列。如果列中包含小列组成的映射表,这就是“超列”。用超列构建的列族叫“超列族”。

Cassandra收到写入请求后,先将待写入数据录入“commit log”,然后将其写入内存中的“memtable”,写入操作在这两步完成表明写入成功。写入请求定期写入SSTable中,SSTable中的缓存一旦写入数据库,就不会继续写入了。如果数据变动,则重新写一张SSTable。无用的SStable用compaction操作回收。一致性的高低级别取决于设置几个节点的commit log写入成功才返回。

Cassandra基本查询有GET, SET, DEL。查询前必须指定键空间:use ecommerce。插入数据的语句举例:SET Customer['lin']['city']='shenzhen';查询GET Customer['lin'];GET Customer['lin']['city'];也可以建立索引。Cassandra也支持一种CQL的类SQL语句,但是不支持jion和子查询,而且where语句的功能不是特别强大

 

适用场景:事件记录,可以使用appname:timestamp为行健,自定义列的方式;博客系统,可以把tag,分类等属性放在不同列中;计数器,如广告展示时间等。

不适合场景:根据数据查询结果来聚合数据的操作,如SUM, AVG;查询模式探索的项目,因为查询模式的改变,列族的设计也需要改变。

 

图数据库

图数据库可以存放实体与实体间的关系。实体对应“节点”,并拥有属性;关系对应“边”,具有方向性;

图数据库遍历“关系”的速度非常快。节点间的关系不在查询时计算,而是在创建时就持久化了。遍历持久化后的关系,要比每次查询实时计算关系快得多。节点间关系可以是domain之间的关系,也可以是secondary关系。

大部分图数据库不支持分布式,Neo4J兼容ACID事务。

图数据库可以使用Gremlin等查询语言。Gremlin是一个可以遍历图的领域特定语言,可以遍历所有市县了Blueprints属性图的图数据库。Neo4J也可以用Cypher查询语言来查询图。查询节点的直接关系,关系数据库也可以做。但是如果关系深度大于1时,图数据库才显示出优势。查询关系时还可以指定单、双向方向。可以计算节点间的最小跳数,即最短路径。

适用场景:互联网数据,尤其是社交数据存储;GIS、路线分配等业务;购物的推荐引擎。

不适合场景:实体属性变更频繁,且影响全局操作。

 

分布式模型

分片。NoSQL数据库大都提供了“自动分片”的功能,可以让数据库自己负责把数据分布到各分片。分片对读取和写入操作的效率提升明显,但是对故障恢复帮助不大。

主从复制。主节点负责存放权威数据,通常负责处理数据的更新。主从复制就是从主节点到从节点的同步。主从复制明显改善需要频繁读取数据的场景性能。主节点出错,从节点依然可以处理读取请求,并可以指定从节点代替出错的主节点。

对等复制。对等复制主要解决主从复制的写入故障恢复能力弱的问题。没有主节点的概念,所有节点都可以处理写入请求。对等复制的最大问题在于数据的一致性,两个节点同时处理写入操作,可能引发写入冲突。两种思路解决一致性的问题,一个是写入前各节点进行协调;另一个是数据库自动处理冲突数据。

一致性的CAP定理。给定一致性Consistency,可用性Availability,分区耐受性Partition tolerance,我们只能同时满足其中的两个属性。一致性无需解释。可用性是指如果客户可以同集群中的某个节点通信,那么该节点就必然能处理读取及写入操作。分区耐受性指,如果发生故障,导致整个集群分为多个无法互相通信的分区时,集群依然可用。一般的分布式系统都在一致性和可用性间平衡或取舍。

版本戳version stamp。NoSQL数据库大都不支持事务,但是可用版本戳来维护数据的一致性。版本戳可以采用计数器实现,也可以是一个很大随机唯一的数字,可以是根据内容生成的hash码,也可以用time stamp。CouchDB的版本戳就是结合了计数器和内容hash码。对等复制的数据库没有统一生成版本戳的地方,需要改进。一个方法是分布式版本控制系统一样,每个节点都有一份版本戳,这种情况需要客户端保存版本戳记录。最常用的一个方法是采用数组式版本戳Vector Stamp。这种版本戳由一系列计数器组成,每个代表一个节点,如[A:43,B:12, C:54]。两个节点同步时,判断两个版本戳,如果新版本戳中有一个变量比旧的小,则表明有版本冲突,需要处理。

 

混合持久化

不同的数据库用来解决不同的问题。只用一种database engine应对所有需求,这种解决版本比较低效。传统关系数据库领域的OLAP(联机分析处理Online analytical processing)和OLTP(联机交易系统Online transaction  processing)差别其实也很大。不同领域数据,如商业逻辑处理引擎,会话,报表,日志的可用性、一致性、备份策略不一定相同,所以需要混合持久化处理。举例来说,以电子商务来说,可以用键值数据库存储购物车信息,用图数据库处理商品推荐。

混合持久化的一个比较好的实现方式就是封装数据库操作为服务。事实上,Riak和Neo4J等数据库都提供了现成的REST API。

企业决定采用混合持久化前,需要考虑许可、支持、工具、升级、驱动、安全等问题。也要考虑不同数据库的监测、备份数据、部署复杂性等技术问题。

NoSQL数据库毕竟还不如关系数据库那么成熟,所以考虑做数据库抽离,或隔离层的考虑。但是如果隔离层的成本过高,还不如直接实现,这个需要具体考量。