NoSQL生态系统

发布时间:2011-12-15

文 / Adam Marcus  译 / iammutex

何为NoSQL?NoSQL不是一个工具,而是由一些具有互补性和竞争性的工具组成的一个概念,是一个生态圈。这些被称为NoSQL的工具,在存储数据的方式上,提供了一种与(基于SQL语言的)关系型数据库截然不同的思路。要想了解NoSQL,必须先了解现有的这些工具,去理解那些引导它们开拓出新的存储领域的设计思路。

NoSQL其名

在给NoSQL下定义之前,我们先来试着从它的名字上做一下解读。顾名思义,NoSQL系统的数据操作接口应该是非SQL类型的。但在NoSQL社区,NoSQL被赋予了更具有包容性的含义,其意为Not Only SQL,即NoSQL提供了一种与传统关系型数据库不同的存储模式,这为开发者提供了关系型数据库之外的另一种选择。

NoSQL的启示

NoSQL运动受到了很多相关研究论文的启示,在所有资料中,最核心的有两个:Google的BigTable论文和Amazon的Dynamo论文。

特性概述

NoSQL系统舍弃了一些SQL标准中的功能,取而代之的是一些简单灵活的功能。NoSQL的构建思想就是尽量简化数据操作,尽量让操作的执行效率可预估。当你去考查一个NoSQL系统时,下面的几点是值得注意的。

  • 数据模型及操作模型:你的应用层数据模型是行、对象还是文档型的呢?这个系统是否能支持你进行一些统计工作呢?
  • 可靠性:当你更新数据时,新的数据是否立刻写到持久化存储中去了?新的数据是否同步到多台机器上了?
  • 扩展性:你的数据量有多大,单机是否能容下?你的读写量需求单机是否能支持?
  • 分区策略:考虑到对扩展性、可用性或者持久性的要求,你是否需要一份数据被存在多台机器上?你是否需要知道或者说你能否知道数据在哪台机器上?
  • 一致性:你的数据是否被复制到了多台机器上?这些不同节点的数据如何保证一致性?
  • 事务机制:业务是否需要ACID事务机制?
  • 单机性能:如果你打算持久化的将数据存在磁盘上,哪种数据结构能满足你的需求(你的需求是读多还是写多)?写操作是否会成为磁盘瓶颈?
  • 负载可评估:对于一个读多写少的应用,诸如响应用户请求的网络应用,我们总会花很多精力来关注负载情况。你可能需要进行数据规模的监控,对多个用户的数据进行汇总统计。你的应用场景是否需要这样的功能呢?

NoSQL数据模型及操作模型

数据库的数据模型指的是数据在数据库中的组织方式,数据库的操作模型指的是存取这些数据的方式。通常数据模型包括关系模型、键值模型以及各种图结构模型。操作语言可能包括SQL、键值查询及MapReduce等。NoSQL通常结合了多种数据模型和操作模型,提供不一样的架构方式。

基于Key值存储的NoSQL数据模型

在键值型系统中,复杂的联合查询以及满足多个条件的数据查询操作就不那么容易实现了,需要换一种思维来建立和使用键名。比如要获取部门号为20的所有员工的信息,应用层可以先获取Key为employee_departments:20的这个列表,然后再循环地拿这个列表中的ID通过获取employee:ID得到所有员工的信息。

  • Key-Value存储

Key-Value存储可以说是最简单的NoSQL存储,每个Key值对应一个任意的数据值。对NoSQL系统来说,这个任意的数据值是什么,它并不关心。比如在员工信念数据库里,employee:30这个Key对应的可能就是一段包含员工所有信息的二进制数据。这个二进制的格式可能是Protocol Buffer、Thrift或者Avro都无所谓。

  • Key-结构化数据存储

Key-结构化数据存储的典型代表是Redis,Redis将Key-Value存储的Value变成了结构化的数据类型。Value的类型包括数字、字符串、列表、集合以及有序集合。除了set/get/delete操作以为,Redis还提供了很多针对以上数据类型的特殊操作,比如针对数字可以执行增、减操作,对list可以执行push/pop操作,通过提供这种针对单个Value进行的特定类型的操作,Redis可以说实现了功能与性能的平衡。

  • Key-文档存储

Key-文档存储的代表有CouchDB、MongoDB和Riak。这种存储结构下Key-Value的Value是结构化的文档,通常这些文档是被转换成JSON或者类似于JSON的结构进行存储。文档可以存储列表,键值对以及层次结构复杂的文档。

  • BigTable的列簇式存储

HBase和Cassandra的数据模型都借鉴自Google的BigTable。这种数据模型的特点是列式存储,每一行数据的各项被存储在不同的列中(这些列的集合称作列簇)。而每一列中每一个数据都包含一个时间戳属性,这样列中的同一个数据项的多个版本都能保存下来。

列式存储可以这样理解:将行ID、列簇号,列号以及时间戳一起,组成一个Key,然后将Value按Key的顺序进行存储。Key值的结构化使这种数据结构能够实现一些特别的功能,最常用的就是将一个数据的多个版本存成时间戳不同的几个值,这样就能方便地保存历史数据。这种结构也能天然地进行高效的松散列数据(在很多行中并没有某列的数据)存储。当然,对于那些很少有某一行有NULL值的列,由于每一个数据必须包含列标识,这又会造成空间的浪费。

图结构存储

图结构存储是NoSQL的另一种存储实现。其指导思想是:数据并非对等的,关系型的存储或者键值对的存储,可能都不是最好的存储方式。图结构是计算机科学的基础结构之一,Neo4j和HyperGraphDB是当前最流行的图结构数据库。

复杂查询

在NoSQL存储系统中,有很多比键值查找更复杂的操作。比如MongoDB可以在任意数据行上建立索引,可以使用Javascript语法设定复杂的查询条件。BigTable型的系统通常支持对单独某一行的数据进行遍历,允许对单列的数据进行按特定条件的筛选。CouchDB允许你创建同一份数据的多个视图,通过运行MapReduce任务来实现一些更为复杂的查询或者更新操作。很多NoSQL系统都支持与Hadoop或者其他MapReduce框架结合来进行一些大规模数据分析工作。

事务机制

与关系型数据库不同的是,NoSQL系统通常注重性能和扩展性,而非事务机制。传统的SQL数据库的事务通常都是支持ACID的强事务机制。ACID的支持使得应用者能够很清楚他们当前的数据状态。对很多NoSQL系统来说,对性能的考虑远在ACID的保证之上。通常NoSQL系统仅提供行级别的原子性保证,也就是说同时对同一个Key下的数据进行的两个操作,在实际执行时是会串行的,保证了每一个Key-Value对不会被破坏。

Schema-free的存储

还有一个很多NoSQL的共同点,就是它通常并没有强制的数据结构约束。即使是在文档型存储或者列式存储上,也不会要求某一个数据列在每一行数据上都必须存在。

数据可靠性

最理想的状态是,数据库会把所有写操作立刻写到持久化存储的设备,同时复制多个副本到不同地理位置的不同节点上,以防止数据丢失。但这种对数据安全性的要求对性能是有影响的,所以不同的NoSQL系统在自身性能的考虑下,在数据安全上采取了不太一样的策略。

单机可靠性

单机可靠性理解起来非常简单,它的定义是写操作不会由于机器重启或者断电而丢失。通常单机可靠性的保证是通过把数据写到磁盘来完成的,而这通常会造成磁盘I/O成为整个系统的瓶颈。下面我们谈谈一些在单机可靠性的保证下提高性能的方法。

  • 控制fsync的调用频率

Redis提供了几种对fsync调用频率的控制方法。应用开发者可以配置Redis在每次更新操作后都执行一次fsync,这样会比较安全,当然也就比较慢。Redis也可以设置成N秒种调用一次fsync,这样性能会更好一点。但这样的后果就是一旦出现故障,最多可能导致N秒内的数据丢失。而对一些可靠性要求不太高的场合(比如仅仅把Redis当Cache用的时候),应用开发者甚至可以直接关掉fsync的调用:让操作系统来决定什么时候需要把数据flush到磁盘(译者注:这只是Redis append only file的机制,Redis是可以关闭aof日志的,另外,Redis本身支持将内存中数据dump成rdb文件的机制,和上面说的不是一回事)。

  • 使用日志型的数据结构

Cassandra、HBase、Redis和Riak都会把写操作顺序的写入到一个日志文件中。相对于存储系统中的其他数据结构,上面说到的日志文件可以频繁地进行fsync操作,这样就把对磁盘的随机写变成顺序写了。

  • 通过合并写操作提高吞吐性能

Cassandra有一个机制,它会把一小段时间内的几个并发的写操作放在一起进行一次fsync调用,这种做法叫group commit。

多机可靠性

由于硬件层面有时会造成无法恢复的损坏,单机可靠性的保证在这时就鞭长莫及了。对于一些重要数据,跨机器做备份保存是必备的安全措施。一些NoSQL系统提供了多机可靠性的支持。

  • Redis采用传统的主从数据同步的方式。
  • MongoDB提供了一种叫Replica Sets高可用架构。
  • Riak、Cassandra和Voldemort提供了一些更灵活的可配置策略,并提供一个可配置的参数N,代表每一个数据会被备份的份数。为了应对整个数据中心出现故障的情况,需要实现跨数据中心的多机备份功能。

横向扩展带来性能提升

横向扩展的目标是达到线性的效果,即如果你增加一倍的机器,那么负载能力应该也能相应的增加一倍。其主要需要解决的问题是如何让数据在多台机器间分布,这里面涉及到分片技术。

分片的意思,就是没有任何一台机器可以处理所有写请求,也没有任何一台机器可以处理对所有数据的读请求。下面我们将会对hash分片和范围分片两种分片方式进行描述。

如非必要,请勿分片

[返回上页]