NoSQL-还是-SQL-?这一篇讲清楚

NoSQL历史
随着大数据时代的到来,越来越多的网站、应用系统需要支撑海量数据存储,高并发请求、高可用、高可扩展性等特性要求,传统的关系型数据库在应付这些调整已经显得力不从心,暴露了许多能以克服的问题。由此,各种各样的NoSQL(Not Only SQL)数据库作为传统关系型数据的一个有力补充得到迅猛发展。

本文将分析传统数据库的存在的相关问题,以及几大类NoSQL如何解决这些问题,希望给大家提供在不同业务场景下,关于存储方面技术选型提供参考。

1 传统数据库缺点

  • 大数据场景下I/O较高
    因为数据是按行存储,即使只针对其中某一列进行运算,关系型数据库也会将整行数据从存储设备中读入内存,导致I/O较高

  • 存储的是行记录,无法存储数据结构

  • 表结构schema扩展不方便
    如要需要修改表结构,需要执行执行DDL(data definition language),语句修改,修改期间会导致锁表,部分服务不可用

  • 全文搜索功能较弱
    关系型数据库下只能够进行子字符串的匹配查询,当表的数据逐渐变大的时候,like查询的匹配会非常慢,即使在有索引的情况下。况且关系型数据库也不应该对文本字段进行索引

  • 存储和处理复杂关系型数据功能较弱
    许多应用程序需要了解和导航高度连接数据之间的关系,才能启用社交应用程序、推荐引擎、欺诈检测、知识图谱、生命科学和 IT/网络等用例。然而传统的关系数据库并不善于处理数据点之间的关系。它们的表格数据模型和严格的模式使它们很难添加新的或不同种类的关联信息。

2 NoSQL解决方案

NoSQL,泛指非关系型的数据库,可以理解为SQL的一个有力补充。

在NoSQL许多方面性能大大优于非关系型数据库的同时,往往也伴随一些特性的缺失,比较常见的,是事务库事务功能的缺失。
数据库事务正确执行的四个基本要素:ACID如下:

要素 名称 描述
A Atomicity
(原子性)
一个事务中的所有操作,要么全部完成,要么全部不完成,不会在中间某个环节结束。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
C Consistency
一致性
在事务开始之前和事务结束以后,数据库数据的一致性约束没有被破坏。
I Isolation
隔离性
数据库允许多个并发事务同时对数据进行读写和修改的能力。隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
D Durability
持久性
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

下面介绍5大类NoSQL数据针对传统关系型数据库的缺点提供的解决方案:

2.1 列式数据库

列式数据库是以列相关存储架构进行数据存储的数据库,主要适合于批量数据处理和即时查询。相对应的是行式数据库,数据以行相关的存储体系架构进行空间分配,主要适合于小批量的数据处理,常用于联机事务型数据处理。

基于列式数据库的列列存储特性,可以解决某些特定场景下关系型数据库I/O较高的问题

2.1.1 基本原理

传统关系型数据库是按照行来存储数据库,称为“行式数据库”,而列式数据库是按照列来存储数据。

将表放入存储系统中有两种方法,而我们绝大部分是采用行存储的。
行存储法是将各行放入连续的物理位置,这很像传统的记录和文件系统。
列存储法是将数据按照列存储到数据库中,与行存储类似,下图是两种存储方法的图形化解释:

按行存储和按列存储模式

2.1.2 常见列式数据库

  • HBase
    HBase
    HBase是一个开源的非关系型分布式数据库(NoSQL),它参考了谷歌的BigTable建模,实现的编程语言为 Java。它是Apache软件基金会的Hadoop项目的一部分,运行于HDFS文件系统之上,为 Hadoop 提供类似于BigTable 规模的服务。因此,它可以容错地存储海量稀疏的数据。

  • BigTable


BigTable是一种压缩的、高性能的、高可扩展性的,基于Google文件系统(Google File System,GFS)的数据存储系统,用于存储大规模结构化数据,适用于云端计算。

2.1.3 相关特性

优点如下:

  • 高效的储存空间利用率

列式数据库由于其针对不同列的数据特征而发明的不同算法使其往往有比行式数据库高的多的压缩率,普通的行式数据库一般压缩率在3:1 到5:1 左右,而列式数据库的压缩率一般在8:1到30:1 左右。
比较常见的,通过字典表压缩数据:
下面中才是那张表本来的样子。经过字典表进行数据压缩后,表中的字符串才都变成数字了。正因为每个字符串在字典表里只出现一次了,所以达到了压缩的目的(有点像规范化和非规范化Normalize和Denomalize)
通过字典表压缩数据

  • 查询效率高

读取多条数据的同一列效率高,因为这些列都是存储在一起的,一次磁盘操作可以数据的指定列全部读取到内存中。
下图通过一条查询的执行过程说明列式存储(以及数据压缩)的优点

执行步骤如下:
i. 去字典表里找到字符串对应数字(只进行一次字符串比较)。
ii. 用数字去列表里匹配,匹配上的位置设为1。
iii. 把不同列的匹配结果进行位运算得到符合所有条件的记录下标。
iv. 使用这个下标组装出最终的结果集。
  • 适合做聚合操作

  • 适合大量的数据而不是小数据

缺点如下:

  • 不适合扫描小量数据
  • 不适合随机的更新
  • 不适合做含有删除和更新的实时操作
  • 单行的数据是ACID的,多行的事务时,不支持事务的正常回滚,支持 I(Isolation)隔离性(事务串行提交),D(Durability)持久性,不能保证 A(Atomicity)原子性, C(Consistency)一致性

2.1.4 使用场景

以HBase为例说明:

  • 大数据量 (100s TB级数据) 且有快速随机访问的需求
  • 写密集型应用,每天写入量巨大,而相对读数量较小的应用
    比如IM的历史消息,游戏的日志等等
  • 不需要复杂查询条件来查询数据的应用
    HBase只支持基于rowkey的查询,对于HBase来说,单条记录或者小范围的查询是可以接受的,大范围的查询由于分布式的原因,可能在性能上有点影响,HBase不适用与有join,多级索引,表关系复杂的数据模型
  • 对性能和可靠性要求非常高的应用
    由于HBase本身没有单点故障,可用性非常高。
  • 数据量较大,而且增长量无法预估的应用,需要进行优雅的数据扩展的
    HBase支持在线扩展,即使在一段时间内数据量呈井喷式增长,也可以通过HBase横向扩展来满足功能。
  • 存储结构化和半结构化的数据

2.2 K-V数据库

指的是使用键值(key-value)存储的数据库,其数据按照键值对的形式进行组织、索引和存储。

KV 存储非常适合不涉及过多数据关系业务关系的数据,同时能有效减少读写磁盘的次数,比 SQL 数据库存储拥有更好的读写性能,能够解决关系型数据库无法存储数据结构的问题

2.2.1 常见 K-V数据库

  • Redis


Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。从2015年6月开始,Redis的开发由Redis Labs赞助,而2013年5月至2015年6月期间,其开发由Pivotal赞助。在2013年5月之前,其开发由VMware赞助。根据月度排行网站DB-Engines.com的数据显示,Redis是最流行的键值对存储数据库。

  • Cassandra

Apache Cassandra(社区内一般简称为C*)是一套开源分布式NoSQL数据库系统。它最初由Facebook开发,用于储存收件箱等简单格式数据,集Google BigTable的数据模型与Amazon Dynamo的完全分布式架构于一身。Facebook于2008将 Cassandra 开源,此后,由于Cassandra良好的可扩展性和性能,被 Apple, Comcast,Instagram, Spotify, eBay, Rackspace, Netflix等知名网站所采用,成为了一种流行的分布式结构化数据存储方案。

  • LevelDB

    LevelDB是一个由Google公司所研发的键/值对(Key/Value Pair)嵌入式数据库管理系统编程库, 以开源的BSD许可证发布。

2.2.2 相关特性

以Redis为例:
优点如下:

  • 性能极高:Redis能支持超过10W的TPS
  • 丰富的数据类型: Redis支持包括String,Hash,List,Set,Sorted Set,Bitmap和hyperloglog
  • 丰富的特性:Redis还支持 publish/subscribe, 通知, key 过期等等特性

缺点如下:
针对ACID,Redis事务不能支持原子性和持久性(A和D),只支持隔离性和一致性(I和C)
特别说明一下,这里所说的无法保证原子性,是针对Redis的事务操作,因为事务是不支持回滚(roll back),而因为Redis的单线程模型,Redis的普通操作是原子性的

大部分业务不需要严格遵循ACID原则,例如游戏实时排行榜,粉丝关注等场景,即使部分数据持久化失败,其实业务影响也非常小。因此在设计方案时,需要根据业务特征和要求来做选择

2.2.3 使用场景

  • 适用场景
    储存用户信息(比如会话)、配置文件、参数、购物车等等。这些信息一般都和ID(键)挂钩
  • 不适用场景
    • 需要通过值来查询,而不是键来查询。Key-Value数据库中根本没有通过值查询的途径。
    • 需要储存数据之间的关系。在Key-Value数据库中不能通过两个或以上的键来关联数据
    • 需要事务的支持。在Key-Value数据库中故障产生时不可以进行回滚。

2.3 文档数据库

文档数据库(也称为文档型数据库)是旨在将半结构化数据存储为文档的一种数据库。文档数据库通常以 JSON 或 XML 格式存储数据。

由于文档数据库的no-schema特性,可以存储和读取任意数据。

由于使用的数据格式是JSON或者BSON,因为JSON数据是自描述的,无需在使用前定义字段,读取一个JSON中不存在的字段也不会导致SQL那样的语法错误,可以解决关系型数据库表结构schema扩展不方便的问题

2.3.1 常见文档数据库

  • MongoDB

  • MongoDB*是一种面向文档的数据库管理系统,由C++撰写而成,以此来解决应用程序开发社区中的大量现实问题。2007年10月,MongoDB由10gen团队所发展。2009年2月首度推出。

  • CouchDB

    Apache CouchDB是一个开源数据库,专注于易用性和成为”完全拥抱web的数据库“。它是一个使用JSON作为存储格式,JavaScript作为查询语言,MapReduce和HTTP作为API的NoSQL数据库。其中一个显著的功能就是多主复制。CouchDB的第一个版本发布在2005年,在2008年成为了Apache的项目。

2.3.2 相关特性

以MongoDB为例进行说明

优点如下:

  • 新增字段简单
    无需像关系型数据库一样先执行DDL语句修改表结构,程序代码直接读写即可
  • 容易兼容历史数据
    对于历史数据,即使没有新增的字段,也不会导致错误,只会返回空值,此时代码兼容处理即可
  • 容易存储复杂数据
    JSON是一种强大的描述语言,能够描述复杂的数据结构

相比传统关系型数据库,文档数据库的缺点主要是对多条数据记录的事务支持较弱,具体体现如下:

  • Atomicity(原子性)
    仅支持单行/文档级原子性,不支持多行、多文档、多语句原子性
  • Isolation(隔离性)
    隔离级别仅支持已提交读(Read committed)级别,可能导致不可重复读,幻读的问题
  • 不支持复杂查询
    例如join查询,如果需要join查询,需要多次操作数据库

MongonDB还是支持多文档事务的Consistency(一致性)和Durability(持久性)

虽然官方宣布MongoDB将在4.0版本中正式推出多文档ACID事务支持,最后落地情况还有待见证。

2.3.3 使用场景

适用场景

  • 数据量很大或者未来会变得很大
  • 表结构不明确,且字段在不断增加,例如内容管理系统,信息管理系统

不适用场景

  • 在不同的文档上需要添加事务。Document-Oriented数据库并不支持文档间的事务
  • 多个文档直接需要复杂查询,例如join

2.4 全文搜索引擎

传统关系型数据库主要通过索引来达到快速查询的目的,在全文搜索的业务下,索引也无能为力,主要体现在:

  • 全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引的数量非常多
  • 全文搜索的模糊匹配方式,索引无法满足,只能用like查询,而like查询是整表扫描,效率非常低

而全文搜索引擎的出现,正是解决关系型数据库全文搜索功能较弱的问题

2.4.1 基本原理

全文搜索引擎的技术原理称为“倒排索引”(inverted index),是一种索引方法,其基本原理是建立单词到文档的索引。与之相对是,是“正排索引”,其基本原理是建立文档到单词的索引。

现在有如下文档集合:

正排索引得到索引如下:

可见,正排索引适用于根据文档名称查询文档内容

简单的倒排索引如下:
简单的倒排索引
带有单词频率信息的倒排索引如下:
带有单词频率信息的倒排索
可见,倒排索引适用于根据关键词来查询文档内容

2.4.2 常见全文搜索引擎

  • Elasticsearch
    Elasticsearch是一个基于Lucene的搜索引擎。它提供了一个分布式,多租户 -能够全文搜索与发动机HTTP Web界面和无架构JSON文件。Elasticsearch是用Java开发的,并根据Apache License的条款作为开源发布。根据DB-Engines排名,Elasticsearch是最受欢迎的企业搜索引擎,后面是基于Lucene的Apache Solr。

  • Solr
    Solr是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。Solr是高度可扩展的,并提供了分布式搜索和索引复制

2.4.3 相关特性

以Elasticsearch为例:
优点如下:

  • 查询效率高 对海量数据进行近实时的处理
  • 可扩展性
    基于集群环境可以方便横向扩展,可以承载PB级数据
  • 高可用
    Elasticsearch集群弹性-他们将发现新的或失败的节点,重组和重新平衡数据,确保数据是安全的和可访问的

缺点如下:

  • ACID支持不足
    单一文档的数据是ACID的,包含多个文档的事务时不支持事务的正常回滚,支持 I(Isolation)隔离性(基于乐观锁机制的),D(Durability)持久性,不支持 A(Atomicity)原子性,C(Consistency)一致性
  • 对类似数据库中通过外键的复杂的多表关联操作支持较弱
  • 读写有一定延时,写入的数据,最快1s中能被检索到
  • 更新性能较低,底层实现是先删数据,再插入新数据
  • 内存占用大,因为Lucene 将索引部分加载到内存中

2.4.4 使用场景

适用场景如下:

  • 分布式的搜索引擎和数据分析引擎
  • 全文检索,结构化检索,数据分析
  • 对海量数据进行近实时的处理
    可以将海量数据分散到多台服务器上去存储和检索

不适用场景如下:

  • 数据需要频繁更新
  • 需要复杂关联查询

2.5 图形数据库


图形数据库应用图形理论存储实体之间的关系信息。最常见例子就是社会网络中人与人之间的关系。关系型数据库用于存储“关系型”数据的效果并不好,其查询复杂、缓慢、超出预期,而图形数据库的独特设计恰恰弥补了这个缺陷,解决关系型数据库存储和处理复杂关系型数据功能较弱的问题。

2.5.1 常见图形数据库

  • Neo4j


Neo4j是由Neo4j,Inc。开发的图形数据库管理系统。由其开发人员描述为具有原生图存储和处理的符合ACID的事务数据库,根据DB-Engines排名, Neo4j是最流行的图形数据库。

  • ArangoDB


    ArangoDB是由triAGENS GmbH开发的原生多模型数据库系统。数据库系统支持三个重要的数据模型(键/值,文档,图形),其中包含一个数据库核心和统一查询语言AQL(ArangoDB查询语言)。查询语言是声明性的,允许在单个查询中组合不同的数据访问模式。ArangoDB是一个NoSQL数据库系统,但AQL在很多方面与SQL类似。

  • Titan

    Titan是一个可扩展的图形数据库,针对存储和查询包含分布在多机群集中的数百亿个顶点和边缘的图形进行了优化。Titan是一个事务性数据库,可以支持数千个并发用户实时执行复杂的图形遍历。

2.5.2 相关特性

以Neo4j为例:

Neo4j 使用数据结构中图(graph)的概念来进行建模。
Neo4j 中两个最基本的概念是节点和边。节点表示实体,边则表示实体之间的关系。节点和边都可以有自己的属性。不同实体通过各种不同的关系关联起来,形成复杂的对象图。

针对关系数据,2种2数据库的存储结构不同:

2种存储结构
Neo4j中,存储节点时使用了”index-free adjacency”,即每个节点都有指向其邻居节点的指针,可以让我们在O(1)的时间内找到邻居节点。另外,按照官方的说法,在Neo4j中边是最重要的,是”first-class entities”,所以单独存储,这有利于在图遍历的时候提高速度,也可以很方便地以任何方向进行遍历


如下优点:

  • 高性能表现
    图的遍历是图数据结构所具有的独特算法,即从一个节点开始,根据其连接的关系,可以快速和方便地找出它的邻近节点。这种查找数据的方法并不受数据量的大小所影响,因为邻近查询始终查找的是有限的局部数据,不会对整个数据库进行搜索

  • 设计的灵活性
    数据结构的自然伸展特性及其非结构化的数据格式,让图数据库设计可以具有很大的伸缩性和灵活性。因为随着需求的变化而增加的节点、关系及其属性并不会影响到原来数据的正常使用

  • 开发的敏捷性
    直观明了的数据模型,从需求的讨论开始,到程序开发和实现,以及最终保存在数据库中的样子,它的模样似乎没有什么变化,甚至可以说本来就是一模一样的

  • 完全支持ACID
    不像别的NoSQL数据库Neo4j还具有完全事务管理特性,完全支持ACID事务管理

缺点如下:

  • 具有支持节点,关系和属性的数量的限制
  • 不支持拆分

2.5.3 使用场景

适用场景如下:

  • 在一些关系性强的数据中,例如社交网络
  • 推荐引擎。如果我们将数据以图的形式表现,那么将会非常有益于推荐的制定

不适用场景如下:

  • 记录大量基于事件的数据(例如日志条目或传感器数据)
  • 对大规模分布式数据进行处理,类似于Hadoop
  • 适合于保存在关系型数据库中的结构化数据
  • 二进制数据存储

3 总结

关系型数据库和NoSQL数据库的选型,往往需要考虑几个指标:

  • 数据量
  • 并发量
  • 实时性
  • 一致性要求
  • 读写分布和类型
  • 安全性
  • 运维成本

常见软件系统数据库选型参考如下:

  • 内部使用的管理型系统
    如运营系统,数据量少,并发量小,首选考虑关系型
  • 大流量系统
    如电商单品页,后台考虑选关系型,前台考虑选内存型
  • 日志型系统
    原始数据考虑选列式,日志搜索考虑选倒排索引
  • 搜索型系统
    例如站内搜索,非通用搜索,如商品搜索,后台考虑选关系型,前台考虑选倒排索引
  • 事务型系统
    如库存,交易,记账,考虑选关系型型+缓存+一致性型协议
  • 离线计算
    如大量数据分析,考虑选列式或者关系型也可以
  • 实时计算
    如实时监控,可以考虑选内存型或者列式数据库

设计实践中,要基于需求、业务驱动架构,无论选用RDB/NoSQL/DRDB,一定是以需求为导向,最终数据存储方案必然是各种权衡的综合性设计

参考

从0开始学架构 —— Alibaba 李运华

NoSQL漫谈

图形数据库 Neo4j 开发实战

大数据时代的 9 大Key-Value存储数据库

事务—— Redis官方文档

MongoDB是如何实现事务的ACID?

MySQL脏读、虚读、幻读

全面梳理关系型数据库和 NoSQL 的使用情景

浅析列式数据库的特点

一分钟搞懂列式与行式数据库

HBase 基本概念

NoSQL Databases, why we should use, and which one we should choose

传统关系数据库与分布式数据库知识点


 上一篇
理解分布式系统中的缓存架构 理解分布式系统中的缓存架构
作者 陈彩华 文章转载交流请联系 caison@aliyun.com本文主要介绍大型分布式系统中缓存的相关理论,常见的缓存组件以及应用场景。 1 缓存概述 2 缓存的分类缓存主要分为以下四类 2.1 CDN缓存基本介绍CDN(Conten
2019-10-13
下一篇 
理解推荐系统 理解推荐系统
本文主要介绍什么是推荐系统,为什么需要推荐系统,如何实现推荐系统的方案,包括实现推荐系统的一些常见模型,希望给读者提供学习实践参考。 1 推荐系统概述为什么需要推荐系统 对于信息消费者,需要从大量信息中找到自己感兴趣的信息,而在信息过载
2019-10-13
  目录