NoSQL简述
NoSQL是什么
NoSQL是 非关系型NoSQL 是一个 非关系型 的 具有互联网场景特性 的 多种DBMS集合。
NoSQL 的命名非常烂(或许NoRelation更为准确),NoSQL 最初的含义是 No SQL,但长期观察下来,发现我们并不能抛弃关系型数据库。
在之后为了自圆其说,又改为 Not Only SQL,但这也有问题,不仅仅是SQL,并不等于不仅仅是关系型DBMS,并且目前很多NoSQL DBMS都在尝试适配SQL语言,那更有歧义了。
再者,RDBMS之前的分层DBMS和网状DBMS属于NoSQL吗?答案是不属于,现在所共识的NoSQL大体上包含K-V DBMS、Column DBMS、Document DBMS和Graph DBMS组成。事实上,NoSQL由互联网公司所发展,在很大程度上受其左右。所以NoSQL我们只需要和现在互联网上的‘NoSQL’含义达成共识即可,避免深入追究。
特别注意:NoSQL 不是某一个或某一类 DBMS, 而是非关系模型下的其他DBMS统称。它只是一个统称,而非一个标准或类型。
NoSQL 的发展
早期使用关系型DBMS实现所有的数据管理,而在互联网快速发展的时代,关系型DBMS无法满足各种各样的场景和需求,因此后续出现了很多针对不同场景和需求的DBMS,而这些互联网场景下的DBMS被统称为 NoSQL。
如面向大数据领域的列式数据库,
为什么需要NoSQL
RDBMS 期望使用 统一的模型 来存储管理网络中的所有数据,这实际上是不合理的。正因为这种不合理性,所以更多的企业和机构(特别是互联网公司)开始考虑使用其他的DBMS来存储管理 不同场景和需求 下的数据。
主要的场景和需求如下:
- 无用的 RDBMS 特性;
-
- 背景:RDBMS实现了事务的ACID,但这些特性在一些场景下并不需要,但由于需要实现ACID,因此使得性能被额外占用了,ACID需要锁、需要Undo和Redo。
- 现状:一些NoSQL实现了事务,但没有实现ACID特性或实现部分特性,还有一些NoSQL完全不支持事务。
- 更灵活的数据结构存储;
-
- 背景:互联网发展的速度非常快,关系型根据表、行和列表示数据的方式不足以适应所有的场景和需求。因此需要更加丰富的数据管理方式来解决这些需求。
- 现状:如使用文档型DBMS来管理文档类数据(报纸、文章、JSON、XML等);使用Hash类型DBMS来管理Hash结构的数据。
- 更高的读写性能;并非所有的NoSQL DBMS读写性能都高于RDBMS,只是基于提升读写性能的需求,从而需要NoSQL。
-
- 背景:关系型DBMS中,通过索引读取数据依旧很慢,而Hash索引结构又会出现很多的问题。并且单台RDBMS往往很难支撑大量的并发。
- 现状:如使用K-V型DBMS来实现数据的快速读写;NoSQL往往支持数据复制,从而实现更高的性能(虽然大多数RDBMS也支持复制,但多个城市、多个中心场景下还是有所欠缺);
- 更多的数据量存储(分布式需求) ;
-
- 背景:互联网爆发时代,大量的用户产生大量的数据,关系型数据库无法对这些数据很好的存储,传统的RDBMS数据都存储在单台服务器上(设计之初就是集中式部署),而单台服务器数据量存储永远是有上限的(垂直扩展),虽然可以实现人为手动分片,但非常复杂,并且由于RDBMS最初的设计是单机存储的,因此一些特性如事务、索引等都无法再使用。
- 现状:NoSQL 通过数据自动分片实现大数据量的存储(水平扩展)。
SQL 和 NoSQL 异同
比较SQL和NoSQL,本质上是 RDBMS 与 NoSQL DBMS 的比较(使用通俗约定的NoSQL含义,而非实际的Not Only SQL含义。即NoSQL DBMS仅指代一些互联网下的非关系型DBMS)。
SQL 最重要的就是 关系模型。NoSQL 最重要的是 分布式、高性能、多种结构存储特性。
- SQL 具有关系特性,存储结构化数据;NoSQL 是非关系型的,即存储结构化数据,也存储半结构化和非结构化数据。
- SQL 的核心是依赖于关系特性对数据进行管理;而NoSQL的核心是依赖于其特有的特性对数据管理。
- SQL 和 NoSQL 通常都具有DBMS的一些特性,如事务、并发读写问题、索引等。但不同的特性下SQL和NoSQL的实现方式不同,如SQL的事务特性为ACID。但NoSQL事务特性大多不支持ACID,甚至都不支持事务。如SQL的索引大多通过tree结构实现,而NoSQL可能是Hash,也可能不需要索引。
- SQL 仅支持少量的分布式特性,如复制或 人工手动分片;而NoSQL同时支持复制和 自动分片。
- SQL 由于其针对关系的设计,使得读写性能有所降低,如Join、GroupBy等;NoSQL 提升了性能,如使用文档存储,避免数据结构的拆分和拼装,使用K-V存储,使得读写性能非常高。
SQL 和 NoSQL 选型
SQL 和 NoSQL 应该是针对不同场景下的不同解决方案,而非互斥。
- RDBMS 实现了事务并支持严格的ACID,如果当前场景和需求不需要ACID特性,那么就可以考虑NoSQL。
- RDBMS 设计之初互联网并不发达,数据量也不大,所以重点在于关系而非存储数据量上。但在当前环境下,网络用户非常多,产生的数据量也大,那么在面对超大数据量时,就需要考虑使用NoSQL存储。
- RDBMS 最主要的就是关系模型,如果一个数据块不适合使用关系模型进行拆分,那么就应该考虑NoSQL。
- RDBMS 在高性能读写场景下需要慎重使用,如果必须要求超高性能,那么就需要考虑NoSQL。
使用场景
无 ACID 场景
大数据量存储场景
- 大字段存储;RDBMS 中大Value 使用NoSQL DBMS存储,而非溢出页等方式被RDBMS管理,条件查询时由于需要加载所有记录与条件比较,因此会包含大字段,造成内存占用和磁盘IO时间变长(MongoDB等)。
- 历史数据存储;一些历史数据,如订单、日志等需要存储,且由于其数据量非常大,因此使用SQL不太合适,那么针对这种场景的NoSQL便是非常合适了。
非关系型结构数据存储场景
- 非结构化数据存储;最主要的就是文档、YAML、XML、JSON等都可以直接存储到文档型 DBMS中(MongoDB等)。如用户的评论信息等不好用关系模型拆分。
高性能读写场景
- 第三方缓存服务;在RDBMS之前使用缓存存储数据提升RDBMS的能力;在网关处使用缓存提升请求性能(Redis等)。
- 大数据量的查询;当数据量变大时,RDBMS通常性能会变差,因此在这种情况下,可以使用NoSQL提升查询性能。
NoSQL类型
Key-Value
数据块以Hash模型进行存储管理。
Document
数据块以文档模型进行存储管理。
Column
数据块以列式模型进行存储管理。
Graph
数据块以图模型进行存储管理。
NoSQL 基础
由于NoSQL是一个DBMS集合,而非某一类DBMS,因此在阐述相关概念时,只能尽可能的抽出共同部分,再举出一些常见NoSQL DBMS例子进以描述。
架构
不同的NoSQL DBMS架构都不太相同,但总体上遵循分布式存储架构。
- Redis 事件驱动架构;数据存储在内存中,从而实现高性能。并且由于其单线程的实现方案,因此不需要考虑并发读写问题。同时使用异步复制实现节点级别的高可用,使用日志实现系统故障后的恢复。
- Etcd 分布式存储架构;数据存储在持久化介质中,提供K-V模型存储和管理数据。 使用Raft解决并发读写问题以及复制。
- 。。。。。。
存储
不同于RDBMS使用文件系统并封装为数据页,NoSQL DBMS的存储方式五花八门,通常使用内存、持久化介质、B-Tree、Hash等方式存储。
索引
索引的目的就是为了优化查询,为数据建立一个目录从而实现快速查询,无论是SQL还是NoSQL,只要查询其中数据时,可以使用数据目录优化,那么就可以使用索引。无非区别在于索引是通过什么结构实现的。
RDBMS 通常使用 B-Tree 建立索引,而一些NoSQL DBMS对索引有各种理解:
- 无索引;
-
- 对于一些NoSQL DBMS来说,不需要数据目录(索引)来优化查询,那么就不需要索引。如一些K-V存储类型DBMS。
- Hash 索引;
-
- 一些比较简单的数据管理,可以使用Hash索引结构实现更快的记录查询。
- Tree 索引;
-
- 一些NoSQL DBMS对于数据块的管理比较复杂,可以通过数据目录进行优化,那么这时就会考虑使用索引,而Tree索引很适合于树形结构的数据存储。如文档存储类型DBMS。
Query Model(NoSQL 语言)
NoSQL 不像关系型DBMS一样,使用标准SQL语言。NoSQL只是非关系型DBMS的统称,各种类型的NoSQL使用不同的属于各自的语言。因此针对NoSQL语言来说需要根据具体的NoSQL类型来理解。
由于 NoSQL 交互语言的混乱性,现在很多 NoSQL 都尝试适配 SQL 语言(同时也说明了NoSQL命名的失败),但由于结构和场景的特殊性,SQL仍然无法替代 NoSQL 的语言。
或许统一所有NoSQL语言本身就是错误的,但如果是统一某一类型的NoSQL语言就已经大大降低NoSQL的复杂性了。
一些 NoSQL DBMS Query Model
| Datastore | Data Model | Query API |
|---|---|---|
| Cassandra | Columnfamily | Thrift |
| CouchDB | Document | map/reduce views |
| HBase | Columnfamily | Columnfamily |
| MongoDB | Document | Cursor |
| Neo4j | Graph | Graph |
| Redis | Collection | Collection |
| Riak | Document | Nested hashes |
| Scalaris | Key/value | get/put |
| Tokyo Cabinet | Key/value | get/put |
| Voldemort | Key/value | get/put |
| 。。。。。 |
事务
事务的目的是保证交易的正确处理,因此提出了ACID特性,而RDBMS中,由于其集中部署设计架构,因此相对来说可以很轻易的实现事务的ACID特性。
而 NoSQL 中,由于NoSQL的核心之一就是分布式,那么就面临一个问题,分布式架构下的分布式ACID如何实现?同时在RDBMS中,也会有此问题,先进的RDBMS实现了复制和人工分片,那么此时由于RDBMS的部署架构变为了分布式,那么也会有分布式ACID的实现问题。
通常分布式ACID问题在应用层或Proxy层解决,但无法彻底解决。并且一些NoSQL实际上也并不需要ACID(这也是一部分NoSQL的使用原因之一),因此一些NoSQL选择放弃事务的实现或仅实现部分事务特性。如MongoDB事务通过分布式事务实现事务的ACID特性;Redis不保证事务的回滚;
一些文章经常直接用RDBMS的ACID与CAP或BASE对比,让人云里雾里。实际上ACID到CAP/BASE中间还间隔了一个分布式ACID。对于BASE的一个前置因素是NoSQL是分布式存储架构。
并发控制
任何提供读写的DBMS都可能有并发读写问题,RDBMS通过并发控制协议尽可能的解决了这个问题,而NoSQL对于并发读写也需要解决。
NoSQL 是一个DBMS集合,因此,NoSQL实现并发控制也是五花八门。如Redis通过单线程避免了此问题;Hypertable通过MVCC技术和锁实现了并发控制;MongoDB通过Update in Place实现并发控制。
故障、恢复和备份
任何数据存储管理系统都需要考虑故障和恢复,非易失性DBMS来说,大多数都依赖于WAL技术实现故障恢复。如MySQL、Redis等。
分布式
RDBMS设计之初就是用于集中式部署,但面对互联网的快速发展,RDBMS不得不做一些改变,一些先进的RDBMS使用复制实现服务高可用,使用手工分片实现数据的扩展性和高并发。更先进的更是实现了自动分片,不过这已经是NewSQL的范畴了,当RDBMS实现了自动分片,并解决了分布式的问题,那么就是NewSQL。
NoSQL由于设计的核心之一就是分布式,因此与分布式化的RDBMS一样,都面临在分布式架构下的一些问题:
- 事务;由于分片模式下的分布式事务ACID特性的实现复杂度,大多数NoSQL如果并非一定需要ACID特性,那么压根就没实现事务或ACID特性(特别是一些不需要分片的NoSQL)。只有一些期望保留事务ACID特新的NoSQL才会在分布式架构下想办法实现。
- 索引;集群部署下,索引实现相比较容易,但分片模型下,数据是分散的,索引实现上就会十分复杂。
- 查询;由于产生了数据复制,那么就会面临数据一致性问题,在分布式架构下,这是最难以解决的问题。
关于分布式相关概念,参考《分布式》。
复制
RDBMS使用复制实现服务级别的高可用,NoSQL同样如此。
分片
RDBMS只能实现人工手动分片(分库分表),而大多数NoSQL设计之初就支持自动分片,还有一些NoSQL不支持分片,因为没有必要,分片最重要的就是提升并发和数据存储量,而如果NoSQL所想要解决的场景没有这些需求,那么就不需要,如Etcd、Zookeeper等。
自动分片和手动分片是一个非常重要的差异,自动分片可以将DBMS系统的复杂度简化非常多。