曾在Thinking in BigDate(三)大数据运作机理与趋势,一文中谈到结构化数据面临的挑战,随着持续增长的海量数据,NoSql应运而生。本文,我们将续续揭开NoSql的神秘面纱,打开非结构化数据的大门(不再过多的探讨关系型数据库的特点)。
原文章总结于《NoSql Distilled》作者:Pramod J.Sadalage ,Martin Fowler著,爱飞翔 译《NoSql 精粹》
大数据技术核心之NoSql(一):
提纲:
数据采集:ETL
数据存储:关系型数据库、NoSql(Not Only SQL)、SQL等
数据管理:(基础架构支持)云存储、分布式文件系统
数据分析与挖掘:(计算结果展现)数据的可视化
起源:
也许在企业界中早已习惯传统的关系型数据库,但随着待处理的数据逐渐增多,集群数据的不断增多。传统数据库已经不能满足更加迥异的数据格式了。于是大家开始不断探索,期待着一种在集群环境中易于编程且执行效率高的大数据处理技术,在此情况下,NoSql应运而生。
为什么,传统关系型数据库开始遇到瓶颈,哪些瓶颈?为什么数据增多,会伴随着非结构性数据的的增多?什么是非结构性数据?NoSql是什么?支持NoSql数据的数据库有哪些?NoSql数据库与关系型数据库的区别?NoSql挑战是什么?为何它会引起关注?什么样的人更应该关注NoSql?等等。
可能这就是一个新事物的诞生必将引起,好事者的一致追捧,提出各种你能想象的问题,想尽一切办法推促它前进。也可能在这个圈子中,总会有一批不知疲倦的人们在不断的探索,不断的寻求改变世界的方案,这也是这批人的引起为豪的乐趣。
NoSql发展如此迅速的原因:由于需要处理的数据越来越多,所以大型系统的扩展方式,由原来在单一计算机上的纵向扩展(scale up),转变为在计算机集群上的横向扩展(scale out)。这也应征了许多NoSql数据库的数据模型所具备的一个重要特征,那就是:可以把内容密切相关的数据组织成一种丰富的结构,并将其显示存储起来,以便作为一个单元(unit)来访问。这种结构,我们暂且称之为聚合(aggregate)。
关系与非关系型数据库对比:
关系型数据库
特征:
1、 持久化数据:能够持久化存储大量数据。这就存在“主存储器=内存”,“后备存储器=硬盘”。而硬盘就可以做持久化数据使用。
2、 并发:并非操作获取数据库中的数据极为困难。而通过“事务”(加“事务错误”)处理机制可以保证数据不受破坏,解决并发问题。
3、 集成:共享数据集成,将多个应用程序的数据保存在同一个数据库中。有利于团队合作开发。同时可以应对多个应用程序的并发机制。
4、 标准模型:这体现在数据库的标准化,有益于开发人员和数据库专家可以学习基本的关系模型,就可以运用到不同的项目中。虽不同的数据库之间存在差异,但核心机制是相同的,SQL、“事务”操作方式也几乎一样。
弊端:
1、 阻抗失谐:令开发者失望的是关系型数据库中的关系模型和内存中的数据结构之间存在差异,这种差异通常称为“阻抗失谐”。关系模型把数据组织成“表”(table)和“行”(row),(你可以理解成“表”、“行”太规范了),更准确的说,更应该是“关系”(relation)和“元组”(tuole)。而在关系模型中,元组是由“键值对”(key-value pair)构成的集合,而关系则是元组的集合。(如果大家稍微了解NoSql(暂且把NoSql定义为非关系型数据库)是基于key-value,上面的话就不难理解了)
2、 集群:不能在集群中运行。随着互联网公司规模急剧增加。如何解决存储问题?这就引入纵向和横向扩展的问题。纵向:需要更强大的计算机。横向:就是采用多个小型计算机组成的集群。毋庸置疑的选择,减低成本又能提高性能。这就遇到问题了:关系型数据库并不是设计集群用的,它们需要一种可以支持集群的文件系统,该文件系统可将数据写入随时可用的磁盘子系统中。
关系型数据库也可以把数据划分为几个集合,并将其分配放在各自独立的服务器上运行,于是就能有效地对数据库分片。这么做虽然能将负载分到多个服务器之中,但是应用程序必须控制所有分片,它要知道数据库中的每份数据放在哪个服务器上才行。而且必须要考虑数据完整性等性质。如此一说,只能说这是“非常之法”,迫不得已之法了。
非关系型数据库(NoSql):
特征:
1、 NoSql数据库不使用或不怎么使用SQL。不能说是优点还是缺点,问题在于,绝大多数人都是习惯了使用SQL,突然不使用,这不是逼着人去改吗?你知道,它们很懒的。这就衍生出一些支持类SQL插件的诞生,不要小看,这里面足够让你大吃一惊(稍后介绍)。
2、 开源(很关键)
3、 抛弃了关系模型
4、 能在集群中运行
5、 “无模式”数据,即不用事先修改结构定义,也可以*添加字段。
6、 Not Only SQL。“不只是SQL”,这中思维方式不仅仅把NoSql当做一项技术,而视为一场变革。
弊端:
1、 鉴于NoSql技术尚未成熟(最近诞生的如:Cassandra、MongoDB、Neo4J和Riak等),所以大部分企业级应用程序开发者目前还应以现有关系型数据库为主,但在前瞻性很强的项目中,可以选用先试先行。
2、 没有规范的定义,每种NoSql解决方案的模型(如:“键值”、“文档”、“列族”、“图”)都不同,导致不同版本的NoSql操作语句之间兼容性的差异。
两个概念:
1、 数据模型:是认知和操作数据时所用的模型。数据模型描述了我们如何同数据库中的数据打交道。我们更关注数据模型。
2、 存储模型:描述数据库内部存储及操作数据的机制。一般不涉及。
聚合数据模型:
聚合
关系模型把待存储的信息分割成元组(行,熟知数据库操作的人都知道:关系型数据库是对行操作的。意思是:读写都是按行操作)元组是种受限数据结构:它只能包含一系列的值,因此不能在元组中嵌套另一元组,也不能包含由值或元组所组成的列表。致使所有操作都必须以元组为目标,而且返回值也必须是元组。
面向聚合使用的方式与之不同,我们通常操作数据时所用的单元,其结构都比元组数据复杂的多。如果能以这种复杂的结构存放列表或嵌套其他记录结构,就解决了上面的问题,后面,“键值数据库”、“文档数据库”、“列族数据库”都使用的是这种更复杂的记录。基于这种复杂的记录简称“聚合”。
为了更明白的阐述什么是“聚合”,我们给出一个示例:
假设一个电子商务网站的用户记录,必须存储用户信息、商品目录、订单、收货地址、账单地址和付款方式等信息。这个应用场景,既可以用关系型数据模型建模,也可以用NoSql数据模型建模,我们来比较两者的优劣。
采用关系型模型建模:(简单示例)
1、 保证各张表格间不会出现重复数据。
2、 维护表格间的“完整性”
图面向关系型数据库的数据模型
图 范例数据
采用聚合模型建模:
图 聚合数据模型 黑色菱形代表各数据在聚合结构中的关系
范例数据,采用JSON格式来表示,因为它是NoSql领域中常用的数据格式
// in customers { "id":1, "name‘:"Martin", "billingAddress":[{"city":"Chicago"}] } // in orders { "id":99, "customerId":1, "orderItems":[ { "productId":27, "price":32.45, "productName":"NoSql Distilled" } ], "shippingAddress":[{"city":"Chicago"}] "orderPayment":[ "ccinfo":"1000-1000-1000" "txnId":"abelif879rft", "billingAdress":{"city":"Chicago"} ], }
这个模型有两个主要聚合:客户(Customer)和订单(Order)。客户数据包含一个账单地址(billing address)列表,订单数据包含订单项(order item)列表,收货地址(shipping address)和付款信息(payment),而付款信息有又含它所对应的账单地址。
同一逻辑地址(账单地址和收货地址所共用的“Chicago”)在示例数据中出现了三次,但是此处我们不用ID来指代,而是直接复制这个地址字符串。如果收货地址和账单地址都不会改变,这么做就很合适。在关系型数据库中,这种情况意味着Address表中的ID=77的那行数据保持不变。若要改变某个地址,需要在该表中创建新行。使用聚合模型后,我们就可以把整个地址结构复制到所有的聚合模型中。(?)
考虑到上述模型与关系型数据库要做权衡一样,这里我么也可以采用非常规的模式,将产品名称直接写入订单项。这种做法在聚合模型中很常见,我们希望在数据交互时尽量减少所需访问的聚合个数。实际上,我么也可以采用另一种方式,把客户下的全部订单放到客户聚合中。
// in customers { "id":1, "name":"Martin", "billingAddress":[{"city":"Chicago"}], “orders”:[ { "id":99, "customerId":1, "orderItems":[ { "productId":27, "price":32.45, "productName":"NoSql Distilled" } ], "shippingAddress":[{"city":"Chicago"}] "orderPayment":[ "ccinfo":"1000-1000-1000" "txnId":"abelif879rft", "billingAdress":{"city":"Chicago"} ], } ] } }
这里就必须谈到如何划分聚合边界的问题(就是上面红字部分涉及的地方),其实在建模过程中,边界的划分并没有标准答案。如果想一次性访问客户的全部订单,那就应该把它们放在一个大的聚合里面,反之,若是每次只想专门处理一笔订单,则应将“客户”和“订单”分离开来。这个都视情况而定,而有的时候这个边界很难区分出来,在有的时候这种聚合反而会带来更多的问题,这时聚合就不适宜了。
面向聚合的影响:
虽然关系映射也能很好的处理各种数据元素之间的关系。上述示例说明:订单由订单项、收货地址及付款信息组成。在关系模型中,可以用“外键”来表示表与表之间的关系,但是这样做无法区分某个关系是否你能表示聚合。因此,数据库无法使用聚合结构来帮助其存储于分布数据。
选用面向聚合模型的决定因素,在于它非常适合在集群中运行。这正是NoSql的关键之处。在集群上运行时,需要把采集数据所需要的节点数降到最低。如果数据库中明确包含聚合结构,加上知道哪些数据要聚合一起操作,这些数据就可以放在一个节点中。(这在前期设计数据库分散在不同节点上非常重要。例如:集群中部署MongoDB收集不同机器上的的日志信息,因为不同机器上收集的日志文件不同,这时候就需要考虑上述说的问题,哪些数据可以放在一个节点上收集更有利于聚合,在实际运用很关键)
关系型数据库支持事务处理,即“ACID事务”,是关系型数据库中的关键中的重点。那么在NoSql中事务处理适合吗?通常情况下,面向聚合的数据库不支持跨越多个聚合的ACID事务。取而代之的是,每次只能在一个聚合结构上执行原子操作,也就是说。如果我们想以原子方式操作多个聚合,那就必须自己写应用代码(这不是废话吗?)。
键值与文档数据模型
键值与文档数据库都是面向聚合的。这些数据库主要通过聚合来构建,且这两类数据库都包含大量的聚合,每个聚合中都包含获取数据所用的键或ID。
两种数据模型的区别:
键值数据库:聚合不透明(数据结构不知道其内部实现细节即可以为外部程序使用)。基本上都是通过键来搜索聚合内容,查询得到全部数据,不能仅仅查询或获取其中的一部分。优势在于:聚合中可以存储任意数据,数据库可能会限制聚合的总大小。
文档数据库:可以看到其结构。提交查询的关键词往往是基于文档的内容,可以查询并获取其中一部分数据,它也许是通过键也许不是通过键获取数据。优势:数据库中虽然限制了其中存放的内容,定义了自己的结构与数据类型,这样的好处,可以更灵活的访问数据。
列族存储模型
早期NoSql数据库是Google的BigTable。BigTable模型的出现影响后来的HBase和Cassandra等NoSql 数据库。在起先,大部分数据库都以行为单元存储数据,尤其在需要提高写入性(写入操作多)的情况下。然而,有些情况下写入操作执行的很少,却常常需要一次性读取行中的很多列。在这种情况下,将所有行的某一组列作为基本数据存储单元,效果会更好。于是“列存储数据库”的命名就来了。
BigTable和它的继承者都遵循“以一组列(就是列族)来存储”的概念。后来大部分的NoSql数据库都可以称为“列族数据库”或“列式数据库”==“图数据库”。
理解列族模型最好的方式可以将其视为两级聚合结构(two-level aggregate structure)。与“键值存储”相同,第一个键通常代表行标识符,用来获取想要的聚合。其于“键值存储”的区别在于,其“行聚合”本身又是一个映射,其中包含更为详细的值。
列族数据库将列组织为列族。每一列都必须是某个列族的一部分,而且访问数据的单元也得是列。这样设计的前提是,某个列族中的数据经常需要一起访问。把聚合分为列族,让数据库将其视为行聚合内的一个数据单元。
图 列族结构表示客户信息
1、 面向行(row-oriented):每一行都是一个聚合(例如:ID-123456的顾客就是一个聚合),该聚合内部包含一些有用数据块(客户信息、订单记录)的列族。
2、 面向列(column-oriented):每个列族都定义了一种记录类型(例如:客户信息),其中每行都表示一条记录。(这里的“行”,指上述图中的行,其实对应数据库中的列族)
面向列,反映了“列”在列族数据库中的重要性。由于数据库了解这些数据通常的分组方式,在存储及访问时利用此信息()。由于列族中可以随意添加列,所以在建模项目清单时,可以把其中每个项目都表示为单独的列。
总结:
上面,大致介绍了三种不同风格的面向聚合的数据模型。三者共同点:集群上运行,聚合是中心环节,因为数据库必须保证将聚合内的数据存放在同一个节点上。聚合是“更新”操作的最小数据单位,对事务控制来说,以聚合为操作单元,大小正好。
·聚合作为交互单元的数据集合。数据库中的ACID操作以聚合为界。
·键值数据看、文档数据库、列族数据库都是面向聚合数据库。
·聚合使数据库在集群上管理数据存储更为方面。
·如果数据交互大都在同一聚合内执行,可选用面向聚合的数据库;若交互操作需要使用多种不同格式的数据,最好选用,非聚合数据库。
后续继续探讨NoSql机理与实现。
Copyright?BUAA