存储高性能[NoSQL]

NoSQL=Not Only SQL,虽然关系型数据库凭借强大的SQL和ACID的属性得到广泛应用,但并不意味着没有缺憾,比如关系型数据库无法存储数据结构存的是行记录,比如关系型数据库的schema扩展很不方便,比如关系型数据库在大数据场景下I/O较高,比如关系型数据库的全文搜索功能比较弱,因此诞生了不同的NoSQL解决方案,这些方案与关系型数据库比在某些应用场景下表现更好,但NoSQL方案带来的优势本质上是牺牲了ACID特性的某个或者某几个,因此NoSQL方案更适合作为SQL的一个有力补充

常见的 NoSQL 方案

  • K-V 存储:解决关系数据库无法存储数据结构的问题,以 Redis 为代表
  • 文档数据库 :解决关系数据库强schema约束的问题,以 MongoDB 为代表
  • 列式数据库 : 解决关系数据库大数据场景下的 I/O 问题,以 HBase 为代表
  • 全文搜索 引擎:解决关系数据库的全文搜索性能问题,以 Elasticsearch 为代表

K-V存储

K”V 存储的全称是 Key-Value 存储,其中 Key 是数据的标识,和关系数据库 中的主键含义 一样, Value 就是具体的数据 。
Red is 是 K-V 存储的典型代表,它是一款开源(基于 BSD 许可)的高性能 K-V 缓存和存储 系统。 Redi s 的 Value 是具体的数据结构,包括 stri n g 、 hash 、 li st 、 set 、 sorted set 、 bitmap 和 hyperloglog ,
所以常常被称为数据结构服务器 。
以 List 数据结构为例, Red is 提供了如下的典型的操作。
• LPOP key ,从队列的左边出队一个元素 。
• LINDEX key index , 获取一个元素 ,通过其索引列表 。
• LLEN key ,获得队列 C List )的长度。
• RPOP key ,从队列的右边出队一个元素 。
如果用 关系数据库来实现以上这些功能,就会变得很复杂。 例如, LPOP 操作是移除井返
回 key 对应的 list 的第一个元素。 如果用关系数据库来存储,为了达到同样目的,则 需要进行 如下操作:
( 1 )每条数据除了数据编号(例如,行 ID ),还要有位置编号,否则没有办法判断|哪条数 据是第一条。注意这里不能用行 ID 作为位置编号,因为我们会往列表头部插入数据。
(2 )查询出第一条数据。
(3 )删除第一条数据。
(4 )更新从第二条开始的所有数据的位置编号。
可以看出关系数据库的实现很麻烦,而且需要进行多次 SQL 操作,性能很低。
Red i s 的缺点主要体现在并不支持完整的 ACID 事务, Redis 虽然提供事务功能,但 Redis
的事务和关系数据库的事务不可同日而语, Redis 的事务只能保证隔离性和一致性 CI 和 C ),无
法保证原子性和持久’1生 CA 和 D )。具体实现原理如下 : • 原子性
Red is 事务不支持原子性, Redis 不支持回滚操作,事务 中间一条命令执行失败,既不会 导致前面己经执行的命令被回跤 ,也不会中断后面的命令的执行。
一致性
Red is 事务能够保证事务开始之前和事务结束以后,数据库的完整性没有被破坏 。
隔离性
Red is 不存在多个事务的问题,因为 Red is 是单进程单线程的工作模式。这种隔离性的 方式也带来一个隐含的问题 : 如果某个客户端通过事务提交了大量的命令,那么会阻塞 其他客户端进行任何操作。
• 持久性
Red is 提供两种持久化的方式,即 RDB 和 AOF 。
RDB 持久化只 备份当前内存中的数据集,事务执行完毕时,其数据还在内存中,并未立即
写入到磁盘,所以 RDB 持久化不能保证 Red is 事务的持久性。
AOF 持久化是先执行命令,执行成功后再将命令追加到日志文件中 。 即使 AOF 每次执行
命令后立刻将日志文件刷盘,也可能丢失 l 条命令数据,因此 AOF 也不能严格保证 Red is 事务 的持久性 。
举一个做博的例子来说 明 Red is 事务和数据库事务 的差别 。 例如,用户 A 关注了用户 B, 实际上产生了两条数据操作 : A 的“ 关注” 列表要增加 B, B 的 “粉丝”列表要增加 A。 如果
用数据库来存储关系数据,通过事务可以保证这两个操作要么同时成功,要么同时失败 。 而使 用 Redis 事务来处理,可能将 B 加入了 A 的关注列表 ,但没有将 A 加入 B 的粉丝列表。
虽然 Red is 并没有严格遵循 ACID 原则 ,但实际上大部分业务也不需要严格遵循 ACID 原 则 。 以上述的微博关注操作为例,即使系统没有将 A 加入 B 的粉丝列表 ,其实业务影响也非常 小,因此我们在设计方案时, 需要根据业务特性和要求来确定是否可以用 Redis ,而不能因为 Red is 不遵循 ACID 原则就直接放弃 。

文档数据库

为了解决关系数据库 schema 带来的问题,文档数据库应运而生,文档数据库最大 的特点就
是 no-schema ,可以存储和读取任意的数据 , 目前绝大部分文档数据库存储的数据格式是 JSON (或者 BSON )。因为 JSON 数据是自描述的,无须在使用前定义宇段,读取一个 JSON 中不存
在的字段也不会导致 SQ L 那样的语法错误。

文档数据库的 no - sc h ema 特性,给业务开发带来如下几个明显的优势。 (I )新增字段简单。
业务上增加新的字段,无须再像关系数据库一样要先执行 DDL 语句修改表结构,程序代码 直接读写即可。
(2 )历史数据不会出错。
对于历史数据,即使没有新增的字段,也不会导致错误,只会返回空值,此时代码进行兼
容处理即可。
(3 )可以很容易存储复杂数据。
JSON 是一种强大的描述语言 ,能够描述复杂的数据结构 。例如,我们设计一个用户管理 系统,用户的信息有 ID 、 姓名、性别、爱好、邮箱、地址、学历信息。其中爱好是列表(因为 可以有多个爱好),地址是一个结构,包括省、市、区楼盘地址,学历包括学校、专业、 入学毕 业年份信息等。如果我们用关系数据库来存储,需要设计多张表,包括基本信息(列 : D、姓 名、性别、邮箱)、爱好(列 : ID 、爱好)、地址(列 : 省、市、区、详细地址)、学历(列 : 入 学时间、毕业时间、学校名称、专业),而使用文档数据库,一个 JSON 就可以全部描述。

通过这个样例我们看到,使用 JSON 来描述数据,比使用关系型数据库表来描述数据方便 和容易得多,而且更加容易理解。
文档数据库的这个特点 , 特别适合电商和游戏这类的业务场景。以电商为例 , 不同商品的 属性差异很大。例如,冰箱的属性和笔记本电脑的属性差异非常大,如下图所示。

即使是同类商品也有不同的属性。例如, LCD 和 LED 显示器,两者有不同的参数指标。 这种业务场景如果使用关系数据库来存储数据 , 就会很麻烦,而使用文档数据库,简单、方便, 扩展新的属性也更加容易。
文档数据库 no - s che ma 的特性带来的这些优势也是有代价的 , 最主要的代价就是不支持事 务。 例如 , 使用 Mon g oDB 来存储商品库存,系统创建订单 的时候首先需要扣减库存,然后再 创建订单 。 这是一个事务操作,用关系数据库来实现就很简单,但如果用 MongoDB 来实现,
就无法做到事务性。异常情况下可能出现库存被扣减了,但订单没有创建的情况 。 因 此某些对 事务要求严格的业务场景是不能使用文档数据库的。
文档数据库另外一个缺点就是无法实现关系数据库的 j o in 操作。例如,我们有一个用户信 息表, 一个订单表,订单表中有买家用户 id 。如果要查询“购买了苹果笔记本用户中的女性用 户”,用关系数据库来实现,一个简单的 join 操作就搞定了 : 而用文档数据库是无法进行 join 查询的,需要查两次 : 一次查询订单表中购买了苹果笔记本的用户,然后再查询这些用户哪些 是女性用户。
综合上述的介绍和分析,文档数据库并不能完全取代关系数据库,更多时候是作为关系数 据库的一种补充。例如,在常见 的电商网站设计中 , 可以使用关系数据库存储商品库存信息、 订单基础信息,而使用文档数据库来存储商品详细信息 , 详细设计如下(仅为举例,实际上要 复杂很多)。

列式数据库

顾名思义,列式数据库就是按照列来存储数据的数据库,与之对应的传统关系数据库被称 为“行式数据库”,因为关系数据库是按照行来存储数据的 。
关系数据库按照行式来存储数据,主要有如下几个优势 :
( 1 )业务 同时读取多个列时效率高,因为这些列都是按行存储在一起的,一次磁盘操作就
能够把一行数据中的各个列都读取到内存中。
(2 )能够一次性完成对一行中的 多 个列的写操作,保证了针对行数据写操作的原子性和一
致性 , 否则如果采用列存储,可能会 出现某次写操作,有的列成功了,有的列失败了,导致数 据不一致 。
我们可以看到 ,行式存储的优势是在特定的业务场景下才能体现,如果不存在这样的业务 场景 ,那么行式存储的优势也将不复存在 , 甚至成为劣势,典型的场景就是海量数据进行统计 。 例如,计算某个城市体重超重 的人员数据,实际上只需要读取每个人的体重这一列并进行统计 即可,而行式存储即使最终只使用 一列,也会将所有行数据都读取出来 。 如果单行用户信息有 l 阻,其中体重只有 4 个字节,行式存储还是会将整行 l 阻 数据全部读取到 内存中,这是明显 的浪费 。 而如果采用列式存储,每个用户只需要读取 4 字节的体重数据即可, νo 将大大减少 。
除了节省 11 0 ,列 式存储还具备更高 的存储压缩比,能够节省更多 的存储空间, 普通的行式 数据库一般压缩率在 3 : 1 到 5 : 1 左右 ,而列式数据库的压缩率一般在 8 : 1 到 30 : 1 左右、,因为单个列的数据相似度相比行来说更高 ,能够达到更高的压缩率 。
同样,如果场景发生变化,列式存储的优势又会变成劣势 。典型 的场景是需要频繁地更新
多个列。因为列式存储将不同列存储在磁盘上不连续的空间,导致更新多个列时磁盘是随机写 操作,而行式存储时同一行多个列都存储在连续的空间, 一次磁盘写操作就可以完成,列式存 储的随机写效率要远远低于行式存储的写效率。此外,列式存储高压缩率在更新场景下也会成 为劣势,因为更新时需要将存储数据解压后更新,然后再压缩,最后写入磁盘 ,
基于上述列式存储的优缺点,一般将列式存储应用在离线的大数据分析和统计场景中,因 为这种场景主要是针对部分列进行操作,且数据写入后就无须再更新删除 。

全文搜索引擎

数据库的缺陷
传统的关系型数据库通过索引来达到快速查询的目的,但是在全文搜索的业务场景下,索
引也无能为力,主要体现在如下几点:
• 全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引的数量会非常多。
• 全文搜索的模糊匹配方式,索引无法满足,只能用 li ke 查询,而 li ke 查询是整表扫描, 效率非常低。
我们举一个具体的例子来看看关系型数据库为何无法满足全文搜索的要求 。假设我们做一 个婚恋网站,其主要目的是帮助程序员找朋友,但模式与传统婚恋网站不同,是“程序员发布 自己的信息,用户来搜索程序员 ” 。程序员 的信息表设计如下表所示 。

基本原理
全文搜索引擎的技术原理被称为“倒排索号|” ( I nverted ind ex ),也常被称为反向索引 、置 入档案或反向档案,是一种索 引 方法,其基本原理是建立单词到文档的索引。之所 以被称为“倒 排”索引,是和“正排索号| ”相对的,“正排索寻| ”的基本原理是建立文档到单词的索引。我们 通过一个简单的样例来说明这两种索引的差异 。

正排索号| 适用于根据文档名称来查询文档内容。例如,用户在网站上单击了“面向对象葵 花宝典是什么”,网站根据文章标题查询文章的内容展示给用户 。
倒排索引适用于根据关键词来查询文档内容。例如,用户只是想看“设计”相关的文章, 网站需要将文章内容中包含“设计”一词的文章都搜索出来展示给用户。
通过上面的样例我们也可以看出, m 排索引和正排索引虽然是相反的两个索引技术,但实 际应用的时候并不是非此即彼,而是将两者结合起来 , 用到倒排索引的地方几乎肯定会用到正 排索引 。 例如,用户搜索文章时用的是倒排索引,系统根据搜索关键词搜索到文档 ID ,然后系 统根据文档 ID 去查询文档名称展示给用户:当用户单击具体的某篇文档时,系统根据文档 ID 查询文档 内容井展示给用户, 此时用的是正排索引 。
• 与数据库结合
全文搜索 引 擎的索引对象是单词和文档,而关系数据库的索引对象是键和行,两者的术语 差异很大 ,不能简单地等同起来。因 此,为了让全文搜索引擎支持关系型数据 的全文搜索,需 要做一些转换操作,即将关系型数据转换为文档数据。
目前常用的转换方式是将关系型数据按照对象的形式转换为 JSON 文挡,然后将 JSON 文 档输入全文搜索引擎进行索引。我们同样以程序员的基本信息表为例,看看如何转换。
将原始表格转换为 JSON 文挡,可以得到 3 个程序员信息相关的文档 :
全文搜索引擎能够基于 JSON 文档建立全文索引,然后快速进行全文搜索。 以 Elasticsearch 为例 , 其索引基本原理如下:
El astci sea 「c h 是分布式的文挡存储方式。官能用i击和检索复杂的数据结构一一序列化成为 JSON 文挡一一以 实时的方式。
在 E l asticsea rch 中 , 每个字段的所有数据都是默认被索引的 。 即每个字段都高为了快速检索设置的专用倒排 索引。 而且 3 不像真他多数的数据库, E能在中目同的查询中使用所有倒排索引,并以惊人的速度返回结果。

需要注意 的是 ,为了描述简单,以上示例只 是单表到 JSON 文挡 的转换 。实际应用中的转 换,并不限定为只能单表到文档的转换,而可以根据搜索需要 , 灵活地从表转换到文档,可 以 单表转换到文挡 ,也可以多表联合起来转换为单一文档。例如, 一个学生管理系统 , 数据库表 可以设计为基础信息表(包含学号、姓名、性别、年龄、籍贯等)、专业信息表(学院、专业等)、
成绩信息表(学科、成绩等)、社团信息表(是否为学生会干部、学生团体等)等多个表格,但 最终转换为 JSON 文档时, 可以一个学生有一个 JSON 文档,文档中包含学生的所有信息。

扫描二维码关注公众号,回复: 11640282 查看本文章

猜你喜欢

转载自blog.csdn.net/dawei_yang000000/article/details/108524005