Redis(一)入门:NoSQL OR SQL,看完这篇你就懂了

本文最后更新于:1 年前

前言

关系型数据库(MySql、Oracle)无法满足我们对存储的所有要求,因此对底层存储的选型,对每种存储引擎的理解非常重要。
MySQL不香吗,为什么还要有NoSQL?请听我慢慢细说!

一、结构化数据、非结构化数据与半结构化数据

文章的开始,了解一下结构化数据、非结构化数据与半结构化数据,因为数据特点的不同,将在技术上直接影响存储引擎的选型。

1、结构化数据

结构化数据,根据定义是指由二维表结构来逻辑表达和实现的数据,严格遵循数据格式与长度规范,也称为行数据。

特点:数据以行为单位,二维表结构下一行数据就表示一个实体的信息,每一列数据的属性都是相同的。

因此关系型数据库刚好契合了结构化数据的特点,关系型数据库也是关系型数据最主要的存储与管理引擎。

2、非结构化数据

非结构数据,根据定义是指数据结构不规则或不完整,没有任何预定义的数据模型,不方便用二维逻辑表来表现数据,例如网页日志、文本文档、图像、视频和音频文件等。

特点:没有固定组织原则的未经过滤的信息,通常被称为原始数据。通过对非结构化数据进行搜索和分析,可以提取有用的信息。

3、半结构化数据

半结构化数据,根据定义是指以非传统方式捕获或格式化的数据。常见的半结构化数据有XML和JSON。

特点:半结构化数据不遵循表格数据模型或关系型数据库的格式,因为它没有固定的架构。

1
2
3
4
5
<person>
<name>linzy</name>
<age>18</age>
<phone>12345</phone>
</person>

这种结构也被成为自描述的结构。
半结构化数据的优点是,与结构化数据相比,它更灵活,更易于扩展。

二、关系型数据库 SQL

1、什么是关系型数据库?

关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库。

2、什么是关系模型?

关系模型是采用二维表格结构表达实体类型及实体间联系的数据模型。关系模型允许设计者通过数据库规范化的提炼,去建立一个信息的一致性的模型。

3、以关系型数据库的方式做存储的架构演进

  • 阶段一:企业刚发展的阶段,最简单,一个应用服务器配一个关系型数据库,每次直接访问数据库进行读写操作。

  • 阶段二:无论是使用MySQL还是Oracle还是别的关系型数据库,数据库通常不会先成为性能瓶颈,通常随着企业规模的扩大,一台应用服务器扛不住上游过来的流量且一台应用服务器会产生单点故障的问题,因此加应用服务器并且在流量入口使用Nginx做一层负载均衡,保证把流量均匀打到应用服务器上。

  • 阶段三:随着企业规模的继续扩大,此时由于读写都在同一个数据库上,数据库性能出现一定的瓶颈,此时简单地做一层读写分离,每次写主库,读备库,主备库之间通过binlog同步数据,就能很大程度上解决这个阶段的数据库性能问题。

  • 阶段四:企业发展越来越好了,业务越来越大了,做了读写分离数据库压力还是越来越大,这时候怎么办呢,一台数据库扛不住,那我们就分几台吧,做分库分表,对表做垂直拆分,对库做水平拆分。以扩数据库为例,扩出两台数据库,以一定的单号(例如交易单号),以一定的规则(例如取模),交易单号对2取模为0的丢到数据库1去,交易单号对2取模为1的丢到数据库2去,通过这样的方式将写数据库的流量均分到两台数据库上。一般分库分表会使用Shard的方式,通过一个中间件,便于连接管理、数据监控且客户端无需感知数据库ip

4、关系型数据库的优点

  • 易理解
    采用二维表结构非常贴近正常开发逻辑(关系型数据模型相对层次型数据模型和网状型数据模型等其他模型来说更容易理解)。

  • 操作方便
    支持通用的SQL(结构化查询语言)语句,通用的SQL语言使得操作关系型数据库非常方便,支持join等复杂查询,SQL + 二维关系是关系型数据库最无可比拟的优点,这种易用性非常贴近开发者。

  • 数据一致性
    支持ACID特性,事务开始前和结束后,数据库的完整性约束没有被破坏 。比如 A 向 B 转账,不可能 A 扣了钱,B 却没收到。在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。 这里的一致性是指系统从一个正确的状态, 迁移到另一个正确的状态, 这是个逻辑层面的正确性。

  • 对事务的支持
    能保证系统中事务的正确执行,同时提供事务的恢复、回滚、并发控制和死锁问题的解决。

  • 数据稳定
    数据持久化到磁盘,没有丢失数据风险,支持海量数据存储,安全可靠。

  • 服务稳定
    最常用的关系型数据库产品MySql、Oracle服务器性能卓越,服务稳定,通常很少出现宕机异常。

5、关系型数据库的不足

随着互联网技术的不断发展,数据也日益增多,关系型数据库面对海量的数据时有些不足也体现出来

  • 高并发下IO压力大
    数据按行存储,即使只针对其中某一列进行运算,也会将整行数据从存储设备中读入内存,导致IO较高。对于网站的并发量高,往往达到每秒上万次的请求,对于传统关系型数据库来说,硬盘 I/O 有限,不能满足很多人同时连接。

  • 为维护索引付出的代价大
    为了提供丰富的查询能力,通常热点表都会有多个二级索引,一旦有了二级索引,数据的新增必然伴随着所有二级索引的新增,数据的更新也必然伴随着所有二级索引的更新,这不可避免地降低了关系型数据库的读写能力,且索引越多读写能力越差。

  • 为维护数据一致性付出的代价大
    数据一致性是关系型数据库的核心,但是同样为了维护数据一致性的代价也是非常大的。我们都知道SQL标准为事务定义了不同的隔离级别,从低到高依次是读未提交、读已提交、可重复度、串行化,事务隔离级别越低,可能出现的并发异常越多,但是通常而言能提供的并发能力越强。那么为了保证事务一致性,数据库就需要提供并发控制与故障恢复两种技术,前者用于减少并发异常,后者可以在系统异常的时候保证事务与数据库状态不会被破坏。对于并发控制,其核心思想就是加锁,无论是乐观锁还是悲观锁,只要提供的隔离级别越高,那么读写性能必然越差。

  • 可扩展性不足
    在基于web的结构中,数据库是最难以水平拓展的,当一个应用系统的用户量和访问量与日俱增的时候,数据库没有办法像web Server那样简单的通过添加更多的硬件和服务节点来拓展性能和负载能力

  • 水平扩展后带来的种种问题难处理
    随着企业规模扩大,一种方式是对数据库做分库,做了分库之后,数据迁移(1个库的数据按照一定规则打到2个库中)、跨库join(订单数据里有用户数据,两条数据不在同一个库中)、分布式事务处理都是需要考虑的问题,尤其是分布式事务处理,业界当前都没有特别好的解决方案。

  • 表结构扩展不方便
    由于数据库存储的是结构化数据,因此表结构schema是固定的,扩展不方便,如果需要修改表结构,需要执行DDL(data definition language)语句修改,修改期间会导致锁表,部分服务不可用。

  • 全文搜索功能弱
    例如like “%中国真伟大%”,只能搜索到”2022年中国真伟大,爱祖国”,无法搜索到”中国真是太伟大了”这样的文本,即不具备分词能力,且like查询在”%中国真伟大”这样的搜索条件下,无法命中索引,将会导致查询效率大大降低

核心问题:关系型数据库在高并发下的性能时有瓶颈的,尤其在O/I读写频繁的情况下,出现的结果就是数据库占用CPU高,SQL执行效率变慢,客户端数据库连接池不够等错误。例如淘宝双十一的情况下,是绝对不可能直接对数据库进行O/I读写操作进行减去库存的。

可能有朋友说,数据库在高并发下的能力有瓶颈,我公司有钱,加CPU、换固态硬盘、继续买服务器加数据库做分库不就好了,问题是这是一种性价比非常低的方式,花1000万达到的效果,换其他方式可能100万就达到了,不考虑人员、服务器投入产出比的Leader就是个不合格的Leader,且关系型数据库的方式,受限于它本身的特点,可能花了钱都未必能达到想要的效果。至于什么是花100万就能达到花1000万效果的方式呢?可以继续往下看,这就是我们要说的NoSQL

三、非关系型数据库 NoSQL

像上文分析的,数据库作为一种关系型数据的存储引擎,存储的是关系型数据,它有优点,同时也有明显的缺点,因此通常在企业规模不断扩大的情况下,不会一味指望通过增强数据库的能力来解决数据存储问题,而是会引入其他存储,也就是我们说的NoSQL

1、什么是非关系型数据库?

NoSQL 数据库(意即”不仅仅是SQL”)并非表格格式,其存储数据的方式与关系表不同。NoSQL 数据库的类型因数据模型而异。主要类型包括文档、键值(KV)、列式和图形。它们提供了灵活的模式,可以随大量数据和高用户负载而轻松扩展。

非关系型数据库,是对关系型数据库的一种补充,特别注意补充这两个字,这意味着NoSql与关系型数据库并不是对立关系,二者各有优劣,取长补短,在合适的场景下选择合适的存储引擎才是正确的做法。

2、常见的NoSQL数据库

  1. 键值数据库:Redis、Memcached、Riak
  2. 图形数据库:Neo4j、InfoGrid
  3. 列式数据库:Bigtable、HBase、Cassandra
  4. 文档数据库:MongoDB、CouchDB、MarkLogic

3、结合NoSql的方式做存储的架构演进


对于那些读远多于写的数据,引入一层缓存,每次读从缓存中读取,缓存中读取不到,再去数据库中取,取完之后再写入到缓存,对数据做好失效机制通常就没有大问题了。通常来说,缓存是性能优化的第一选择也是见效最明显的方案。

但是,缓存通常都是键值型存储且容量有限(基于内存),无法解决所有问题,于是再进一步的优化,我们继续引入其他NoSql:

数据库、缓存与其他NoSQL并行工作,充分发挥每种NoSQL的特点。当然NoSQL在性能方面大大优于关系型数据库的同时,往往也伴随着一些特性的缺失,比较常见的就是事务功能的缺失

4、NoSQL 数据库四种类型

1)键值(KV)NoSql(代表—-Redis)

键值数据库是一种较简单的数据库,其中每个项目都包含键和值。Redis又是键值数据库中应用最广泛的NoSQL,键值数据库以Redis为例,键值数据库的优点:

  • 数据基于内存,读写效率高。
  • 键值型数据,时间复杂度为O(1),查询速度快。

键值数据库最大的优点就是高性能,利用Redis自带的BenchMark做基准测试,TPS可达到10万的级别,性能非常强劲,键值数据库非常适合需要存储大量数据但无需执行复杂查询来检索数据的使用案例。常见的使用案例包括存储用户首选项或缓存

Ridis也同样有所有键值数据库都有的比较明显的缺点:

  • 只能根据键去查值,key → value,无法根据值去查键。
  • 查询方式单一,只有key → value方式,不支持条件查询,多条查询的唯一做法就是数据冗余,但会极大浪费存储空间。
  • 内存始终是有限的,无法支持海量数据的存储。
  • 由于键值数据库的存储时基于内存的,所以存在数据丢失的风险。

键值数据库非常适合需要存储大量数据但无需执行复杂查询来检索数据,也就是作为缓存来使用:

  • 读操作多于写操作
  • 读取能力强
  • 没有持久化的需求,可以容忍数据丢失的风险,丢失了就再查询写入即可

==键值数据库作为缓存的流程例子:==
根据用户id查询用户信息,每次根据用户id去缓存中查询一把,查到数据直接返回,查不到去关系型数据库里面根据id查询一把数据写到缓存中去。

2)图形NoSql(代表—-Neo4j)

图形数据库是以点、边为基础存储单元,以高效存储、查询图数据为设计原理的数据管理系统。图形数据库可以直观地可视化关系,是存储、查询、分析高度互联数据的最优办法。

Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。图形数据库以Neo4j为例,图形数据库的优点:

  • 更直观的模型
    图数据模型直接还原业务场景,相比传统数据模型更直观,提升产品与工程师的沟通效率。

  • 更简洁的查询语言
    图数据库支持查询语言在关联查询中更简洁,以最通用的Cypher图查询语言为例,复杂关联查询时代码量比SQL大幅降低,能够帮助程序员提升开发效率。

  • 更高效的关联查询性能
    图数据库在处理关联性强的数据以及天然的图问题场景时具有强大的·关联查询性能优势·。因为传统关系型数据库在进行关联查询时需要做表连接(JOIN),会把设计的表数据全部加载到内存中,涉及到大量的IO操作及内存消耗。而图数据库对关联查询有针对性的优化,能防止局部数据的查询引发全部数据的读取,可以高效查询关联数据。

图形数据库不足之处:

  • 可能需要对整个图做计算,不利于图数据分布存储

什么样的场景适合用图数据库

  • 需要高性能深度关系查询与分析时,例如:金融反欺诈、社交网络分析、网络安全等。
  • 业务动态,需要灵活数据模型时,例如:商品推荐、供应链管理、资产与权限管理等。
  • 需要执行复杂关系分析与推理时,例如:智能问答、新药研发、设备故障检测等。

与关系数据库对比:

在关系型数据库设计的时候需要进行严格的数据规范化,将数据分成不同的表并删除其中的重复数据,这种规范化保证了数据的强一致性并支持ACID事务。然而,这也对关系查询带来的限制。

快速的实现逐行访问是关系型数据库的设计原理之一,当数据的数据之间形成复杂的关联时,跨表的关联查询增加,就会出现问题。虽然可以通过将存在不同表中的不同属性进行关联从而实行复杂查询,但是开销是非常大的。

与关系型数据库相比,图数据库把关系也映射到数据结构中,对于关联度高的数据集查询更快,尤其适合那些面向对象的应用程序。同时图数据库可以更自然的扩展到大数据应用场景,因为图数据库Schema更加灵活,所以更加适合管理临时或不断变化的数据。

关系型数据库对大量的数据元素进行相同的操作时通常更快,因为这是在其自然的数据结构中操作数据。图数据库在很多方面比关系型数据库更具有优势,而且变得越来越流行,但是图形数据库和关系型数据库并非是简单的替代关系,在具体应用场景中图数据库可以带来性能的提升和降低延迟才是适合的应用场景。

3)列式NoSql(代表—-HBase)

列式数据库针对快速检索数据列进行了优化,通常用于分析应用程序。适用于数据库表的列式存储是分析查询性能的一个重要组成部分,因为它极大地降低了整体磁盘 I/O 要求,并减少了需要从磁盘载入的数据量。

列式NoSql是基于列式存储的,那么什么是列式存储呢,列式NoSql和关系型数据库一样都有主键的概念,区别在于关系型数据库是按照行组织的数据:

关系型数据库:

关系型数据库是基于行存储方式的,例子中每行有name、phone、address三个字段,即使存在Null值的数据,它也是占空间的。

列式数据库,它是按每一列进行组织的数据:


列式数据库这样的好处:

  • 查询时只有指定的列会被读取,不会读取所有列(与关系数据库最主要的区别)。
  • 存储上节约空间,Null值不会被存储,一列中有时候会有很多重复数据(尤其是枚举数据,性别、状态等),这类数据可压缩,行式数据库压缩率通常在3:1–5:1之间,列式数据库的压缩率一般在8:1–30:1左右。
  • 列数据被组织到一起,一次磁盘IO可以将一列数据一次性读取到内存中。

关于数据压缩,我们对字典表压缩作为举例:

要构建表级别字典,系统会扫描表以查找重复模式。系统将检查所有行(而不仅仅是检查这些行的某些字段或者某些部分)以了解是否存在重复的条目或模式。

收集重复的条目之后,数据库管理器将构建一个压缩字典,并为这些条目指定简短的数字键。通常来讲,文本字符串的压缩机率高于数字数据;压缩数字数据涉及将一个数字替换为另一个数字。根据要替换的数字的大小,节省的存储空间可能不像压缩文本时节省的存储空间那么多。

关于列式数据库的优缺点总结:
优点:

  • 海量数据无限存储,PB级别数据随便存,底层基于HDFS(Hadoop文件系统),数据持久化
  • 读写性能好,只要没有滥用造成数据热点,读写基本随便玩
  • 横向扩展在关系型数据库及非关系型数据库中都是最方便的之一,只需要添加新机器就可以实现数据容量的线性增长,且可用在廉价服务器上,节省成本
  • 本身没有单点故障,可用性高
  • 可存储结构化或者半结构化的数据
  • 列数理论上无限,HBase本身只对列族数量有要求,建议1~3个

缺点:

  • HBase是Hadoop生态的一部分,因此它本身是一款比较重的产品,依赖很多Hadoop组件,数据规模不大没必要用,运维还是有点复杂的
  • KV式,不支持条件查询,或者说条件查询非常非常弱吧,HBase在Scan扫描一批数据的情况下还是提供了前缀匹配这种API的,条件查询除非定义多个RowKey做数据冗余
  • 不支持分页查询,因为统计不了数据总数

4)文档型NoSql(代表—-MongoDB)

文档数据库将数据存储在类似于 JSON(JavaScript 对象表示法)对象的文档中。每个文档包含成对的字段和值。这些值通常可以是各种类型,包括字符串、数字、布尔值、数组或对象等,并且它们的结构通常与开发者在代码中使用的对象保持一致。

由于字段值类型和强大的查询语言的多样性,因此文档数据库非常适合各种各样的使用案例,并且可以用作通用数据库。它们可以横向扩展以适应大量数据,因此文档型NoSql的出现是解决关系型数据库表结构扩展不方便的问题的。

MongoDB是文档型NoSql的代表产品,同时也是所有NoSql产品中的明星产品之一,因此这里以MongoDB为例。

关系型数据库是按部就班地每个字段一列存,在MongDB里面就是一个JSON字符串存储。关系型数据可以为name、phone建立索引,MongoDB使用createIndex命令一样可以为列建立索引,建立索引之后可以大大提升查询效率。

其他方面而言,就大的基本概念,二者之间基本也是类似的:

因此,对于MongDB,我们只要理解成一个Free-Schema的关系型数据库就完事了,它的优缺点比较一目了然。
优点:

  • 没有预定义的字段,扩展字段容易
  • 相较于关系型数据库,读写性能优越,命中二级索引的查询不会比关系型数据库慢,对于非索引字段的查询则是全面胜出

缺点:

  • 多表之间的关联查询不支持(虽然有嵌入文档的方式),join查询还是需要多次操作
  • 空间占用较大,这个是MongDB的设计问题,空间预分配机制 + 删除数据后空间不释放,只有用db.repairDatabase()去修复才能释放

四、总结:关系型数据库与NoSQL间的对比

1、何时选用关系型数据库,何时选用非关系型数据库?

如何选择关系型数据库和非关系型数据库,需要考虑两个问题:

  1. 数据间是否有一致性的需求?
  2. 是否核心数据且有多字段组合查询场景
  1. 非关系型数据库都是通过牺牲了ACID特性来获取更高的性能的,假设两张表之间有比较强的一致性需求,那么这类数据是不适合放在非关系型数据库中的。
  2. 核心数据不走非关系型数据库,例如用户表、订单表,但是这有一个前提,就是这一类核心数据会有多种查询模式,例如用户表有ABCD四个字段,可能根据AB查,可能根据AC查,可能根据D查,假设核心数据,但是就是个KV形式,比如用户的聊天记录,那么HBase一存就完事了。
  3. 非核心数据尤其是日志、流水一类中间数据千万不要写在关系型数据库中,这一类数据通常有两个特点:
    - 写远高于读
    - 写入量巨大
  4. 一旦使用关系型数据库作为存储引擎,将大大降低关系型数据库的能力,正常读写QPS不高的核心服务会受这一类数据读写的拖累。

2、选用非关系型数据库,使用哪种非关系型数据库?

NoSQL 代表产品 解决关系型数据库的什么问题 优点 缺点
键值(KV)NoSql Redis (1)需要存储大量数据但无需执行复杂查询来检索数据的使用
(2)热点KV型数据读写QPS高,读写性能受高QPS写数据的直接影响
(1)数据基于内存,读写效率高。
(2)键值型数据,时间复杂度为O(1),查询速度快。
(3)原子命令的特性可用于分布式锁
(1)数据无法持久化。
(2)不支持条件查询。
(3)基础内存存储,存储空间有限
图形NoSql Neo4j (1)数据的数据之间形成复杂的关联时,跨表的关联查询增加,开销很大。
(2)管理临时或不断变化的数据。
(1)利用图结构相关算法(最短路径、节点度关系查找等)。
(2)图数据库支持查询语言在关联查询中更简洁。
(3)图数据库在处理关联性强的数据以及天然的图问题场景时具有强大的关联查询性能优势。
(1)可能需要对整个图做计算,不利于图数据分布存储。
(2)高度结构化的数据处理能力不及关系型数据库。
列式NoSql HBase (1)海量数据存储后读写性能低。 (1)支持海量数据存储,特别适合数据增长不可预估的场景。
(2)KV方式读写性能高。
(3)横向扩展方便。
(4)可直接部署廉价服务器,成本低
(1)基本没有条件查询能力。
(2)不支持分页查询。(3)运维复杂。
(4)需要开发者有一定的能力。
文档型NoSql MongoDB (1)表Schema扩展不方便 (1)没有预定义的Schema,可随意变更字段。
(2)命中二级索引时性能高于关系型数据库,非索引字段查询远远胜出。
(1)空间占用大。

参考文章:
《Sql Or NoSql,看完这一篇你就懂了》
NoSQL四种类型参考百度百科。


Redis(一)入门:NoSQL OR SQL,看完这篇你就懂了
https://gopherlinzy.github.io/2022/09/19/redis-NoSQL-SQL/
作者
孙禄毅
发布于
2022年9月19日
许可协议