阅读 3614

浅谈常见的NoSQL技术方案和选型

前言

在互联网和大数据的背景下,越来越多的网站、应用系统需要支撑 海量数据存储高并发请求高可用高可扩展性 等特性要求。传统的 关系型数据库 已经难以应对类似的需求,各种各样的 NoSQLNot Only SQL)数据库因此而产生。

本文将分析 传统数据库 的存在的问题,以及几类 NoSQL 如何解决这些问题。在不同的 业务场景 下,作出正确的 数据存储 技术选型。

正文

1. 传统数据库缺点

缺点 解释说明
大数据场景下 I/O 较高 因为数据是按 行存储,即使只针对其中 某一列 进行运算,关系型数据库也会对 整行数据 进行扫描,从存储设备中 读入内存,导致 I/O 较高
结构化存储 不够灵活 存储的是 行记录,无法存储 灵活的数据结构
表结构 schema 扩展不方便 如要需要修改 表结构,需要执行执行 DDLdata definition language)语句修改,修改期间会导致 锁表,部分服务不可用
全文搜索 功能较弱 关系型数据库只能够进行 子字符串匹配查询,当表的数据逐渐变大的时候,即使在有 索引 的情况下,like 扫表查询的匹配会 非常慢
难以 存储处理 复杂 关系型数据 传统的关系数据库,并不擅长处理 数据点之间 的关系

2. NoSQL简介

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

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

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

针对传统 关系型数据库 的不足,下面介绍常见的 5 大类 NoSQL 解决方案:

3. 列式数据库

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

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

3.1. 基本原理

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

将表放入存储系统中有两种方法,而我们绝大部分是采用 行存储 的。行存储法是将 各行 放入 连续的物理位置,这很像传统的记录和文件系统。

列存储法 是将数据 按照列 存储到数据库中,与 行存储 类似,下图是两种存储方法的图形化解释:

3.2. 常见列式数据库

3.2.1. HBase

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

3.2.2. BigTable

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

3.3. 相关特性

3.3.1. 优点

  • 高效的储存空间利用率

列式数据库 针对不同列的 数据特征 而发明了 不同算法,使其比 行式数据库 高的多的 压缩率。普通的 行式数据库 一般压缩率在 3:15:1 左右,而 列式数据库 的压缩率一般在 8:130:1 左右。

比较常见的,通过 字典表 压缩数据:

下面才是那张表本来的样子。经过 字典表 进行 数据压缩 后,表中的 字符串 才都变成 数字。正因为每个字符串在 字典表 里只 出现了一次,所以达到了 压缩 的目的。

  • 查询效率高

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

执行步骤如下:

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

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

3.3.2. 缺点

  • 不适合扫描 小量数据

  • 不适合 随机的更新

  • 不适合做含有删除和更新的 实时操作

  • 单行数据 支持 ACID事务操作多行数据事务操作,不支持事务的 正常回滚,支持 (Isolation)隔离性、(Durability)持久性,不能保证 (Atomicity)原子性、(Consistency)一致性。

3.4. 应用场景

列数据库的适用场景,以 HBase 为例说明:

  • 适合 大数据量 (100TB 级数据),有 快速随机访问 的需求。

  • 适合 写密集型 应用,每天写入量巨大,而 读数量相对较小 的应用,比如 IM历史消息游戏日志 等等。

  • 适合不需要 复杂查询 条件来查询数据的应用。HBase 只支持基于 rowkey 的查询,对于 HBase 来说,单条记录 或者 小范围的查询 是可以接受的。大范围 的查询由于 分布式 的原因,可能在 性能 上有点影响。HBase 不适用于有 join多级索引表关系复杂 的数据模型。

  • 性能可靠性 要求非常高的应用。

  • 由于 HBase 本身没有 单点故障可用性 非常高。

  • 适合 数据量较大,而且 增长量 无法预估的应用,需要进行优雅的数据扩展的应用。HBase 支持 在线扩展,即使在一段时间内,数据量呈 井喷式增长,也可以通过 HBase 横向扩展 来满足功能。

  • 存储 结构化半结构化 的数据。

4. K-V数据库

4.1. 基本概念

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

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

4.2. 常见K-V数据库

4.2.1. Redis

Redis 是一个使用 ANSI C 编写的 开源支持网络基于内存可选持久性键值对存储 数据库。Redis 是目前最流行的 键值对存储 数据库之一。

4.2.2. Cassandra

Apache Cassandra(社区内一般简称为 C*)是一套 开源的分布式 NoSQL 数据库系统。它最初由 Facebook 开发,用于储存 收件箱 等简单格式数据,集 Google BigTable数据模型Amazon Dynamo完全分布式 架构于一身。Cassandra 是一种流行的 分布式结构化 数据存储方案。

4.2.3. Memcached

Memcached 是一个 开放源代码高性能、分配的 内存对象缓存系统。用于加速动态 web 应用程序,减轻关系型数据库负载。它可以应对 任意多个连接,使用 非阻塞的网络 IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个 Hash 表,Memcached 自管理这些 Hash 表。

Memcached 简单而强大。它简单的设计促进 迅速部署,易于发现所面临的问题,解决了很多 大型数据缓存

4.2.4. LevelDB

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

4.3. 相关特性

K-V 数据库的相关特性,以 Redis 为例说明:

4.3.1. 优点

  • 性能极高

Redis 单机最高能支持超过 10WTPS

  • 丰富的数据类型

Redis 支持包括 StringHashListSetSorted SetBitmapHyperloglog 等数据结构。

  • 丰富的特性

Redis 还支持 publish/subscribe通知key 过期 等特性。

4.3.2. 缺点

  • Redis 事务 不能支持 原子性持久性AD),只支持 隔离性一致性IC)。

这里所说的 无法保证原子性,是针对 Redis事务操作,因为事务是 不支持回滚roll back),而因为 Redis单线程模型Redis 的普通操作是 原子性的

4.4 应用场景

4.4.1. 适用场景

  • 适合存储 用户信息(比如 会话)、配置文件参数购物车 等等。这些信息一般都和 ID 挂钩。

4.4.2. 不适用场景

  • 不适合需要通过 来查询,而不是 来查询。Key-Value 数据库中根本没有通过 值查询 的途径。

  • 不适合需要储存 数据之间的关系。在 Key-Value 数据库中不能通过 两个或以上 的键来 关联数据

  • 不适合需要支持 事务 的场景。在 Key-Value 数据库中 故障产生 时不可以进行 回滚

5. 文档型数据库

5.1. 基本概念

文档数据库 用于将 半结构化数据 存储为 文档 的一种数据库。文档数据库通常以 JSONXML 格式存储数据。

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

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

5.2. 常见文档数据库

5.2.1. MongoDB

MongoDB 是一个基于 分布式文件存储 的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的 高性能 数据存储解决方案。

MongoDB 是一个介于 关系数据库非关系数据库 之间的产品,是非关系数据库当中功能 最丰富,最像关系数据库的 NoSQL

5.2.2. CouchDB

CouchDB 是用 Erlang 开发的 面向文档分布式 数据库,用于存储 半结构化 的数据,比较类似 luceneindex 结构。

CouchDB 支持 RESTful API,它使用 JSON 作为 存储格式JavaScript 作为 查询语言MapReduceHTTP 作为 APINoSQL 数据库。其中一个显著的功能就是 多主复制 功能。除此之外,CouchDB 构建在强大的 B- 树储存引擎 之上。

5.3. 相关特性

文档型数据库 的相关特性,以 MongoDB 为例进行说明:

5.3.1. 优点

  • 新增字段简单不需要像关系型数据库一样,先执行 DDL 语句 修改表结构,程序代码 直接读写 即可。

  • 容易兼容 历史数据。对于历史数据,即使没有新增的字段,也不会导致错误,只会返回 空值,此时 代码兼容处理 即可。

  • 容易存储复杂数据。JSON 是一种强大的 描述语言,能够描述复杂的 数据结构

5.3.2. 缺点

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

  • Atomicity(原子性):仅支持 单行/文档级原子性,不支持 多行多文档多语句原子性

  • Isolation(隔离性):隔离级别仅支持 已提交读Read committed)级别,可能导致 不可重复读幻读 的问题。

  • 不支持 复杂查询。例如 join 查询,如果需要 join 查询,需要 多次操作数据库

5.4. 应用场景

5.4.1. 适用场景

  • 数据量 很大或者未来会变得很大。

  • 表结构不明确,且 字段不断增加,例如内容管理系统,信息管理系统。

5.4.2. 不适用场景

  • 在不同的文档上需要添加 事务Document-Oriented 数据库并不支持 文档间的事务

  • 多个文档之间需要 复杂的查询,例如 join 操作。

6. 全文搜索引擎

6.1. 基本概念

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

  • 全文搜索的条件,可以随意 排列组合,如果通过索引来满足,则索引的 数量非常多

  • 全文搜索的 模糊匹配方式,索引 无法满足,只能用 like 进行查询,而 like 查询是 整表扫描效率非常低

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

6.2. 基本原理

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

  • 现在有如下文档集合:

  • 正排索引 得到索引如下:

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

  • 简单的 倒排索引 如下:

  • 带有 单词频率 信息的 倒排索引 如下:

可见,倒排索引 适用于根据 关键词 来查询 文档内容

6.3. 常见全文搜索引擎

6.3.1. ElasticSearch

ElasticSearch 是一个基于 Apache Lucene搜索引擎。它提供了一个 分布式多租户 对全文搜索引擎。ElasticSearch 是用 Java 开发的,对外提供 RESTful Web 接口。根据 DB-Engines 排名,ElasticSearch 是最受欢迎的 企业搜索引擎

6.3.2. Solr

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

6.4. 相关特性

全文搜索引擎,以 ElasticSearch 为例说明:

6.4.1. 优点

  • 查询效率高,适用于对 海量数据 进行 近实时 的处理。

  • 可扩展性

  • 基于 集群 环境可以方便 横向扩展,可以承载 PB 级的数据。

  • 支持 高可用ElasticSearch 集群弹性灵活,可以发现新的或失败的节点,重组重新平衡 数据,确保数据是 安全可访问的

6.4.2. 缺点

  • 事务的 ACID 支持不足,单一文档 的数据是支持 ACID 的。对于 多个文档事务操作,不支持事务的 正常回滚。支持(Isolation)隔离性(基于 乐观锁机制)和(Durability)持久性,不支持(Atomicity)原子性,(Consistency)一致性。

  • 对类似数据库中,通过 外键 进行 多表关联的复杂操作支持较弱。

  • 读写 有一定 延时,写入的数据,最快 1s 中能被检索到。

  • 更新 性能较低,底层实现是 先删数据,再 插入新数据

  • 内存占用大,因为 Lucene索引部分 加载到 内存 中。

6.5. 应用场景

6.5.1. 适用场景

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

6.5.2. 不适用场景

  • 数据需要 频繁更新

  • 需要 复杂关联查询

7. 图形数据库

7.1. 基本概念

图形数据库 应用 图形理论 存储 实体 之间的 关系信息。最常见例子就是 社会网络中人与人之间的关系。关系型数据库 用于存储这种 关系型数据 的效果并不好,其查询 复杂缓慢超出预期

图形数据库 的独特设计弥补了这个缺陷,解决 关系型 数据库 存储处理复杂关系型数据 功能较弱的问题。

7.2. 常见图形数据库

7.2.1. Neo4j

Neo4j 是一个 高性能的NOSQL 图形数据库,它将 结构化数据 存储在 “图形网络上” 而不是 “表中”。它是一个 嵌入式的基于磁盘的、具备完全的 事务特性Java 持久化引擎

Neo4j 也可以被看作是一个 高性能的图引擎。程序员工作在一个 面向对象的灵活的网络结构 下而不是 严格静态表中

7.2.2. ArangoDB

ArangoDB 是一个 原生多模型 数据库系统。数据库系统支持 三个 重要的 数据模型键/值文档图形)。

ArangoDB 包含一个 数据库核心统一查询语言 AQLArangoDB 查询语言)。查询语言是 声明性的,允许在 单个查询组合 不同的 数据访问模式ArangoDB 是一个 NoSQL 数据库系统,但 AQL 在很多方面与 SQL 都类似。

7.3. 基本原理

图形数据库,以 Neo4j 为例说明:

  • Neo4j 使用 数据结构 中图(graph)的概念来进行 建模

  • Neo4j 中两个最基本的概念是 节点节点 表示 实体 则表示 实体之间的关系节点 都可以有自己的 属性。不同 实体 通过各种不同的 关系 关联起来,形成复杂的 对象图

针对关系数据,两种数据库的 存储结构 分别如下:

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

7.4. 相关特性

7.4.1. 优点

  • 高性能表现

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

  • 设计的灵活性

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

  • 开发的敏捷性

数据模型 直接明了,从需求的讨论开始,到程序开发和实现,基本上不会有大的变化。

  • 完全支持ACID

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

7.4.2. 缺点

  • 节点关系 和它们的 属性 的数量被 限制

  • 不支持 拆分

7.5. 应用场景

7.5.1. 适用场景

  • 在一些 关系性强 的数据应用,例如 社交网络

  • 推荐引擎,将数据以 图的形式 表现,非常有益于推荐的制定。

7.5.2. 不适用场景

  • 记录大量 基于事件 的数据,如日志记录、传感器数据。

  • 对大规模 分布式数据 进行处理,类似于 Hadoop

  • 不适用于应该保存在 关系型数据库 中的 结构化数据

  • 二进制数据存储

小结

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

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

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

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

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


欢迎关注技术公众号: 零壹技术栈

零壹技术栈

本帐号将持续分享后端技术干货,包括虚拟机基础,多线程编程,高性能框架,异步、缓存和消息中间件,分布式和微服务,架构学习和进阶等学习资料和文章。

评论