首页 > 安全资讯 >

初识NoSQL

16-10-12

nosql数据库入门。NoSQL这个词首先出现在20世纪90年代末,本身是一个开源的关系数据库,由于其不依赖SQL语句对数据操作,所以起名NoSQL。

1. 什么是NoSQL

NoSQL这个词首先出现在20世纪90年代末,本身是一个开源的关系数据库,由于其不依赖SQL语句对数据操作,所以起名NoSQL

而我们现在所提到的NoSQL可以解释为“Not only SQL”或者”Non relational SQL”,意为非关系型数据库,其概念源于2009年的一场技术聚会。

2. 数据模型

2.1 关系数据模型

传统的设计中,关系数据模型一直占主导地位,直观上看,数据在关系数据库中的存储就是一组表格,表头表示每一列数据的含义,表格内的每一行表示一条数据实体,正式的说法即“关系”和”元组”。例如一个用户下单的关系模型可以如下图表示:
这里写图片描述
其对应在关系数据库中的表达可以建立以下几张表

Customer Id Name
  1001 Martin

Order CustomerId OrderId AddressId Payment
  1001 2001 3001 ¥500.00

Address AddressId CustomerId City Street
  3001 1001 Beijing Chang’an

Product ProductId OrderId Name Price
  4001 2001 Juice ¥3.00

这里为了简单说明,就不再对映射进行分离

2.2 聚合数据模型

考虑以编程的方法实现,每一个实体作为一个POJO类,画出对应的UML类图,其对应关系如下图:
这里写图片描述
用JSON来表示对应的数据,可以得到下面两个JSON结构:

// Customer
{
    "id":1001,
    "name":"Martin",
    "Address":[{"id":3001,"City":"Beijing","Street":"Chang'an"}]
}
// Order
{
    "id":2001,
    "CustomerId":1001,
    "Payment":"¥500.00",
    "Address":[{"id":3001,"City":"Beijing","Street":"Chang'an"}],
    "Product":[{"id":4001,"Name":"Juice","Price":"¥3.00"}]
}

这个模型对应两个主要的聚合:客户(Custome)和订单(Order)。如果我们在业务操作流程中不会包含单独对订单的操作或者在查看客户的时候希望直接读取到其所有订单,可以将上述的聚合关系改为:
这里写图片描述
对应的JSON结构为:

// Customer
{
    "id":1001,
    "name":"Martin",
    "Address":[{"id":3001,"City":"Beijing","Street":"Chang'an"}],
    // Order
    "Order":[
        {
            "id":2001,
            "CustomerId":1001,
            "Payment":"¥500.00",
            "Address":[{"id":3001,"City":"Beijing","Street":"Chang'an"}],
            "Product":[{"id":4001,"Name":"Juice","Price":"¥3.00"}]
        }]
}

聚合的划分没有标准答案,取决于你的业务如何操作数据。

关系映射能很好地捕捉各种数据元素及其关系,但是却没有聚合的概念。在关系数据模型中,我们可以通过外键来描述实体之间的关系,但是外键无法明确将关系表示为聚合,即关联或依赖关系同样适用外键表示。在关系型数据库的数据模型中,没有聚合这一概念,我们称之为聚合无知(aggregate-ignorant)。聚合无知不一定是坏事,在上面说过,聚合边界的划分没有一个标准答案,以上面的实体关系为例,在查看顾客订单的业务中,将订单作为顾客的一个聚合结构将带来很多便利,而在对所有历史订单进行归类分析时,如果将订单设置为聚合结构反而增加了业务的复杂度。

聚合对数据库带来的一个重要影响是数据库的一致性。在关系型数据库中,通过事务的ACID属性来保证数据库的强一致性ACID保证一致性的重点是原子性,在单一事务操作中更新多表多行数据,原子性保证操作要么完全成功,要么完全失败。在聚合数据模型中,通常不支持跨多个聚合的ACID事务。在聚合数据模型的领域中,出现了CAP定理最终一致性的概念来保证数据库的一致性。具体在NoSQL中是如何保证一致性,将在后面的文章讨论。

2.3 图模型

图模型的催生动机在于处理如下图的网状数据结构
这里写图片描述
图数据库专门擅长捕捉此类信息,不过它实际处理的数据规模会大很多,比如社交网络、产品偏好等包含复杂关系的数据库分析时,图数据库会有比较理想的效果。

图数据库的基本数据模型很简单,即边和节点组成的有向连通图,大部分情况下,都是沿有向图的边浏览数据库来寻找符合条件的数据,在上面的有向图中,我们要查找节点1、4创建的节点,可以首先找到节点1和4,然后沿着以1、4为起点,权值标记为created的边找到相交节点。

图数据库与聚合数据库的明显差异,在于其关注点在数据之间的关系

3. NoSQL数据库

根据业内当前主流的划分,NoSQL数据库共分为四类:键值数据库、文档数据库、列族存储和图数据库。针对上述的数据模型,键值数据库、文档数据库和列族数据库对应聚合数据模型,图数据库对应图存储模型。

3.1 键值数据库

KV型NOSQL系统起源于Amazon开发的Dynamo系统(Amazon AWS提供的DynamoDB就是这货),可以把它理解为一个分布式的hashmap,支持SEG/GET元操作。

一个完整的分布式KV系统会将KEY按策略尽量均匀地散列在不同的节点上。其中一致性哈希是比较优雅的散列策略,它可以保证当某个节点挂掉时,只有该节点的数据需要重新散列。作为对比,若采用取模哈希策略,则集群有节点不可用时,取模的分母N发生变化,会导致几乎所有的KEY都要重新散列,代价太高。

大多数KV NOSQL通常不会关心存入的value到底是什么,在它看来,那只是一堆字节而已,所以开发者也无法通过value的某些属性来获取整个value。如果开发者有根据value的部分字段查找数据的需求,那应该考虑使用文档型NOSQL系统。

典型的KV型NOSQL系统:Memcached, Redis及DynamoDB

3.2 文档数据库

对于需要跟具有层次文档结构的数据打交道的开发者来说,文档型NOSQL系统提供了最自然的存储模式,它支持读/写一些标准格式的文档数据(典型如XML, YAML和JSON,甚至支持2进制的BSON格式)。

在最简单的应用中,文档数据可以通过其ID进行读写操作,此时,可以将文档型NOSQL系统看作是K-V系统。

但文档型NOSQL系统更普遍的应用场合是根据文档的某个属性字段来获取整个文档。根据属性快速获取包含该属性的所有文档的操作是通过索引来实现的,也即文档数据在写入时,系统会对某些文档属性建立索引,从而支持高效地反查操作。而维护索引是有代价的,因此,文档型NOSQL数据库适用于读多写少的场合。

需要注意的是,对于单个文档的读写,文档型NOSQL系统可以保证原子操作,但批量写入的事物原子性目前还不能由系统保证,需要开发者在应用程序中显式处理。

此外,目前大多数文档型NOSQL系统需要用户来规划数据在集群多个实例间的sharding策略,因此,系统的水平扩展问题需要在选型时重点考虑,例如MongoDB早期版本的auto sharding在运维上就容易坑人,导致其一直被诟病。作为对比,主流的KV NOSQL系统和列式NOSQL系统在底层实现时就支持自动sharding,通常无需开发者花费很大精力来处理。

典型的文档型NOSQL系统:MongoDB和Apache CouchDB

3.3 列族数据库

早期最具影响力的一种NoSQL数据库是谷歌的BigTable,后续出现的列族数据库都受到BigTable的影响。BigTable根据其字面理解翻译为”大表格数据模型”,而在其实际使用中,将其理解为二级聚合结构(two-level aggregate structure)更合适。其存储方式与键值存储相似,键代表内容标识,而值表示的是另一层键值映射。
这里写图片描述

面向行:每一行都是一个聚合,例如ID为1001的顾客是一个聚合,该聚合内部包含了该顾客的基本数据如姓名,和一些数据块儿如地址,订单的列族。 面向列:每一个列族都定义了一种记录类型,列族中的每一个列都可以作为一个新的聚合进行扩展。

将列族视为一个表格仍然不是很直观,个人理解,将列族的存储方式拓扑为一个树状结构似乎更合适,以行的键值作为根节点向下扩展,每一个基本列数据都是一个叶子节点,而超列则可以向下继续扩展为子树。

典型的列式NOSQL系统:BigTable, Cassandra, HBase

3.4 图数据库

见图模型。

典型的图式NOSQL系统:Neo4j,FlockDB

4. 为什么使用NoSQL数据库

阻抗失谐
关系数据库经过长期的开发使用,其结构和功能都非常完善。然而关系数据库一直存在一个问题,即关系模型和内存中的数据结构存在差异,这种现象称为阻抗失谐。现在普及的各种ORM框架如Hibernate,iBatis等,都在一定程度上解决了阻抗失谐的问题。然而过分依赖ORM框架的话在一定程度上可能造成数据库操作性能下降。
为了方便数据的读取,考量业务模型比较符合聚合结构,则适用NoSQL。

大数据和集群
当前互联网访问的数据和流量急剧增加,当数据超过单台机器上数据库的存储限制,就需要对数据库进行集群迁移。关系型数据库布置在集群时需要“共享磁盘子系统”来运行。它们使用一种可以支持集群的文件系统,该文件系统可将数据写入随时可用的磁盘子系统中,但是这样一来,磁盘子系统就成了集群的软肋。关系数据库也可以把数据划分成几个集合,将其分别放在独立的服务器上运行,这么做虽然讲负载分散到多个服务器上,但是应用程序需要控制数据的分片操作。而且,参照完整性、事务、一致性控制等也无法跨分片执行。
为了解决关系数据库与集群不协调的问题,引入NoSQL数据库。

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

相关文章
最新文章
热点推荐